Board Game Regressor

Before we dive into machine learning, we’re going to explore a dataset, and figure out what might be interesting to predict. The dataset is from

BoardGameGeek, and contains data on 80000 board games. Here’s a single boardgame on the site. This information was kindly scraped into csv format by Sean Beck, and can be downloaded here. The dataset contains several data points about each board game.

https://www.dataquest.io/blog/machine-learning-python

The first step in our exploration is to read in the data and print some quick summary statistics and we enhanced the tutorial with a decision tree feature importance.

One of the nice things about Scikit-learn is that it enables us to try more powerful algorithms very easily. One such algorithm is called

random forest. The random forest algorithm can find nonlinearities in data that a linear regression wouldn’t be able to pick up on.

import re, math
from collections import Counter
import numpy as np
import pandas
import matplotlib.pyplot as plt

text1 = 'How can I be a geologist?'
text2 = 'What should I do to be a geologist?'

class Similarity():
    def compute_cosine_similarity(self, string1, string2):
         print(string1, string2)
         # intersects the words that are common
         # in the set of the two words
         intersection = set(string1.keys()) & set(string2.keys())
         # dot matrix of vec1 and vec2
         numerator = sum([string1[x] * string2[x] for x in intersection])

         # sum of the squares of each vector
         # sum1 is the sum of text1 and same for sum2 for text2
         sum1 = sum([string1[x]**2 for x in string1.keys()])
         sum2 = sum([string2[x]**2 for x in string2.keys()])

         # product of the square root of both sum(s)
         denominator = math.sqrt(sum1) * math.sqrt(sum2)
         if not denominator:
            return 0.0
         else:
            return round(numerator/float(denominator),4)

    def text_to_vector(self,text):
        WORD = re.compile(r'\w+')
        words = WORD.findall(text)
        print(words)
        return Counter(words)

    def text_to_vector2(self,atext):
        atex = atext.lower().split(" ")
        print(atex)
        return Counter(atex)

    # Jaccard Similarity
    def tokenize(self,string):
        return string.lower().split(" ")

    def tokenize2(self,string):
        return string.lower().split(" ")

    def jaccard_similarity(self, string1, string2):
        intersection = set(string1).intersection(set(string2))
        union = set(string1).union(set(string2))
        return len(intersection)/float(len(union))

similarity = Similarity()

# vector space
vector1 = similarity.text_to_vector2(text1)
vector2 = similarity.text_to_vector2(text2)

# split words into tokens
token1 = similarity.tokenize2(text1)
token2 = similarity.tokenize2(text2)

cosine = similarity.compute_cosine_similarity(vector1, vector2)
print ('Cosine Similarity:', cosine)

jaccard = similarity.jaccard_similarity(token1,token2)
print ('Jaccard Similarity:', jaccard)

#https://www.dataquest.io/blog/machine-learning-python/

games = pandas.read_csv(r"C:\maXbox\mX46210\DataScience\games.csv")
# Print the nameof the columns in games.
print(games.columns)
print(games.shape)

#plt.hist(games["average_rating"])
#plt.show()

games[games["average_rating"] == 0]
print(games[games["average_rating"] == 0].iloc[0])

games = games[games["users_rated"] > 0]
# Remove any rowy with missing values.
games = games.dropna(axis=0)
print(games.shape)

from sklearn.cluster import KMeans

kmeans_model = KMeans(n_clusters=5, random_state=1)
good_columns = games._get_numeric_data()
kmeans_model.fit(good_columns)
labels = kmeans_model.labels_
#centroids = kmeans_model.centroids_
print(labels)

#print(kmeans_model.cluster_centers_)
centers = np.array(kmeans_model.cluster_centers_)

plt.plot()
plt.title('maXbox k-means centroids')
colors = ['b', 'g', 'c','r','y']
markers = ['o', 'v', 's']

"""
x1 = np.array([3, 1, 1, 2, 1, 6, 6, 6, 5, 6, 7, 8, 9, 8, 9, 9, 8])
x2 = np.array([5, 4, 6, 6, 5, 8, 6, 7, 6, 7, 1, 2, 1, 2, 3, 2, 3])
"""
#"""
#label = kmeans_model.fit_predict(good_columns)
#print(label)
X= good_columns.values
u_labels = np.unique(labels)
for i in u_labels:          #(u_labels, kmeans_model.labels_):
    #plt.plot(labels[:i,0], labels[:i,1], color=colors[l], marker=markers[l],ls='None')
    plt.scatter(X[labels == i ,0] , \
                X[labels == i ,1],color=colors[i],label=u_labels[i]) #color=colors[i])-labels=i
    # plt.scatter(centers[:,0], centers[:,1], marker="x", color=colors)
    #plt.xlim([0, 10])
    #plt.ylim([0, 10])
#"""
#plt.scatter(centers[:,0], centers[:,1], marker="x", color='r')
plt.scatter(centers[:,0] ,centers[:,1], marker="x", s= 250, color= 'k') #'k' - colors)
plt.legend()
plt.show()

from sklearn.decomposition import PCA

#"""
pca_2 = PCA(3)  #2 or 3?
plt.title('maXbox PCA fit_transform')
plot_columns = pca_2.fit_transform(good_columns)
plt.scatter(x=plot_columns[:,0], y=plot_columns[:,1], c=labels)
# plt.scatter(centers[:,0], centers[:,1], marker="x", color='b')
plt.show()
#"""
print(games.corr()["average_rating"])

# Get all the columns from the dataframe.
columns = games.columns.tolist()
# Filter the columns to remove ones we don't want.
columns = [c for c in columns if c not in ["bayes_average_rating","average_rating","type","name"]]

# Store the variable we'll be predicting on.
target = "average_rating"

# Import a convenience function to split the sets.
from sklearn.model_selection import train_test_split

# Generate the training set.  Set random_state to be able to replicate results.
train = games.sample(frac=0.8, random_state=1)
# Select anything not in the training set and put it in the testing set.
test = games.loc[~games.index.isin(train.index)]
# Print the shapes of both sets.
print('train shape: ',train.shape)
print('test shape: ',test.shape)

# Import the linearregression model.
from sklearn.linear_model import LinearRegression

# Initialize the model class.
model = LinearRegression()
# Fit the model to the training data.
model.fit(train[columns], train[target])

# Import the scikit-learn function to compute error.
from sklearn.metrics import mean_squared_error
# Generate our predictions for the test set.
predictions = model.predict(test[columns])
# Compute error between our test predictions and the actual values.
print(mean_squared_error(predictions, test[target]))
print(mean_squared_error(test[target], predictions))

from sklearn.metrics import r2_score
print(r2_score(test[target], predictions))

# Import the random forest model.
from sklearn.ensemble import RandomForestRegressor

# Initialize the model with some parameters.
model = RandomForestRegressor(n_estimators=100, min_samples_leaf=10, random_state=1)
# Fit the model to the data.
model.fit(train[columns], train[target])
# Make predictions.
predictions = model.predict(test[columns])
# Compute the error.
print('mse ',mean_squared_error(predictions, test[target]))
print('r2 ',r2_score(test[target], predictions))

plt.title('maXbox Game Ratings Feature Importance')
#print(model.feature_importances_)
plt.xlabel("maXbox Random Forest Feature Importance")
plt.barh(columns, model.feature_importances_)
#plt.show()
sorted_idx = model.feature_importances_.argsort()
#TypeError: only integer scalar arrays can be converted to a scalar index
# plt.barh(np.array([columns[sorted_idx]]), model.feature_importances_[sorted_idx])
#plt.barh(columns[sorted_idx], list(model.feature_importances_[sorted_idx]))
#plt.xlabel("maXbox Random Forest Feature Importance")
plt.show()
 

#https://github.com/ThaWeatherman/scrapers/blob/master/boardgamegeek/spider.py
#https://mljar.com/blog/feature-importance-in-random-forest/
#----app_template_loaded_code----
#----File newtemplate.txt not exists - now saved!----

And the output:

C:\maXbox\mX46210\maxbox4>py ..\DataScience\gamegeek_similarity_py.txt
[‘how’, ‘can’, ‘i’, ‘be’, ‘a’, ‘geologist?’]
[‘what’, ‘should’, ‘i’, ‘do’, ‘to’, ‘be’, ‘a’, ‘geologist?’]
Counter({‘how’: 1, ‘can’: 1, ‘i’: 1, ‘be’: 1, ‘a’: 1, ‘geologist?’: 1}) Coun
{‘what’: 1, ‘should’: 1, ‘i’: 1, ‘do’: 1, ‘to’: 1, ‘be’: 1, ‘a’: 1, ‘geologi: 1})
Cosine Similarity: 0.5774
Jaccard Similarity: 0.4
Index([‘id’, ‘type’, ‘name’, ‘yearpublished’, ‘minplayers’, ‘maxplayers’,
‘playingtime’, ‘minplaytime’, ‘maxplaytime’, ‘minage’, ‘users_rated’,
‘average_rating’, ‘bayes_average_rating’, ‘total_owners’,
‘total_traders’, ‘total_wanters’, ‘total_wishers’, ‘total_comments’,
‘total_weights’, ‘average_weight’],
dtype=’object’)
(81312, 20)
id 318
type boardgame
name Looney Leo
yearpublished 0
minplayers 0
maxplayers 0
playingtime 0
minplaytime 0
maxplaytime 0
minage 0
users_rated 0
average_rating 0
bayes_average_rating 0
total_owners 0
total_traders 0
total_wanters 0
total_wishers 1
total_comments 0
total_weights 0
average_weight 0
Name: 13048, dtype: object
(56894, 20)
[2 1 1 … 4 4 4]
id 0.304201
yearpublished 0.108461
minplayers -0.032701
maxplayers -0.008335
playingtime 0.048994
minplaytime 0.043985
maxplaytime 0.048994
minage 0.210049
users_rated 0.112564
average_rating 1.000000
bayes_average_rating 0.231563
total_owners 0.137478
total_traders 0.119452
total_wanters 0.196566
total_wishers 0.171375
total_comments 0.123714
total_weights 0.109691
average_weight 0.351081
Name: average_rating, dtype: float64
train shape: (45515, 20)
test shape: (11379, 20)
1.8239281903519875
1.8239281903519875
0.268394771387396
mse 1.414465540054245
r2 0.4326364435453288

C:\maXbox\mX46210\maxbox4>

Below, we exploit the fact that every Pandas row has a unique index to select any row not in the training set to be in the testing set.

# Generate training set. Set random_state to be able to replicate results.
train = games.sample(frac=0.8, random_state=1)
# Select anything not in the training set and put it in the testing set.
test = games.loc[~games.index.isin(train.index)]
# ~ means Not!
Fitting a target function with different-degree polynomials – Deep Learning for NLP and Speech Recognition, Springer 2018,

Given a line and a point not on the line, construct a line through the point and perpendicular to the line.  The trick here is to determine the slope of the given line,  m, and take advantage of the fact that the slope of  a perpendicular line is -1/m.

HMI Metall Edition

TEE Modell News 2024

Aktuell in den Handel gekommen ist ja im 2023 schon das Modell der PIKO Re 4/4 I 10034. Es zeigt die Ausführung so wie sie ab 1973 in den Betrieb kam, also mit dem neuen SBB-Logo in Form einer Frontplatte, die breitere Wippe und den vier Einschnitten 
im Stromabnehmersockel für den Verkehr nach Lindau (DB/ÖBB Wipe).

Nun kommt neu auch die 10033 von Piko in den Handel. Das Modell, als Winterneuheiten 2024/25 deklariert, überzeugt durch gelungenen Formenbau, 
feingliedrige Pantographen aus Metall, einen vorbildgerechten Dachgarten und zahlreiche angesetzte Details.

Foto Quelle: Piko

-teetime2_re44_10033_48024_96889.jpg

-teetime2_re44_10033_48024_96889_2.jpg



Interessant zu wissen ist, dass die Re 4/4 I 10033 2.Serie die letzte in der TEE Lackierung war. Es waren ja die vier Lok Nr. 10033, 10034, 10046 und 10050 mit rot/beigen Anstrich.

Zudem kommt für den Schweizer Fachhandel die grüne SBB Re 4/4 I 10040 
mit kleinen TEE-Logos an den Fronten (DC 96886, DC digital Sound 96887, AC digital Sound 96888)

 in den Handel. Das Modell hat übrigens fahrtrichtungsabhängiger Lichtwechsel 3x weiss vorne und 1x weiss hinten.

Mittlerweile ist es schon erstaunlich und beachtenswert, was PIKO an Modellen nach Schweizer Vorbildern anbietet. Wobei für viele Deutsche oder Franzosen ärgerlich ist, das wieder einmal Schweiz exklusiv ist.

Als Referenz zur Re 4/4 I liste ich kurz die Märklins auf. Die mir somit bekannten, neueren Re 4/4 I Märklin Loks (mit C Sinus Kompaktmotor ) sind folgende Loks:

–  Lok 10015, grün, ohne TEE Logo, Gussgehäuse und C Sinus Motor, Modell Nr. 39420 aus dem Jahr 2006 – 2009
–  Lok 10033, TEE Schema, Zentral Mittelmotor, von der Zugpackung des TEE Bavaria, Modell #26557
–  Lok 10040, grün, mfx und Sound, Modell Nr. 37044 , aus dem Jahr 2010
–  Lok 10044, grün mit rotem TEE Frontschild, mfx und Sound, aus der Rheingold Zugpackung 26604

Eine weiter Neuheit und mein persönlicher Favorit ist die Hornby/Jouef E-Lok CC 6511. Die als Mistral firmierte
Lok hat optimale Laufeigenschaften und authentisches Design. Die Lieferung erfolgt in 
Silber nit Mistral-Logo und im Kern werkelt ein 5-poliger Motor mit Schrägwicklung. Bei Arwico ist noch 
ein Lagerbestand von 4 erhältlich. Ich hab die Lok für Testfahrten gleich neben 
die CC 6512 Etendard gestellt, siehe Foto:


– teetime1_mistral_20240330_095942.jpg

Die CC 6511 war eine der letzten 1,5-kV-Lokomotiven, die man ohne Leistungselektronik entwickelt hat.

Sie konnte sowohl Personenzüge mit 200 km/h als auch Güterzüge mit 100 km/h ziehen. Ihr Design basiert auf den ursprünglichen “nez cassés” (gebrochene Nasen als Anspielung auf die geneigten Windschutzscheiben) der CC 40100, die ebenfalls von Paul Arzens gestaltet wurden.

Im nächsten TEE-Time erfolgt ein Bericht zu den neuen 21000er Modellen Cisalpin von Arnold, L.S. und Jouef.

Aus Katalog 1982 K.P.E.V. – Königlich Preußische Eisenbahn-Verwaltung
Beschreibung:Personenwagen/Durchgangswagen, 2-achsig, 1. Klasse, beige (creme)/rot
Bemerkung:mit Fantasielackierung einer imaginären Privatbahn, Zuglaufschild ´Central´

Grauzone

Grauzone was a band from Berne, Switzerland that was active and disbanded in the early 1980s. Grauzone is most famous for their 1981 hit “Eisbär”.

Max Kleiner at Grauzone Bollwerk
Walkman

Tensions had always been seething regarding the direction of the band and in early 1982 Marco quit as well. In his place, Ingrid Berney (bass) joined Grauzone for what was going to be the band’s last recording session.

cents microtonal music

G9

Discography of G9

G9 Music Video of the year 1984 from the single hit “Antarktisch Mädchen” from the Album G9 – Zukunft.

G9 Antarktisch Mädchen Music Video
Backside of Zukunft

Record History

Artist: G9
Title: Live in Biel
Songs: Generatom / Glas Pinguin / X 4 / Princip / Kaltkult // Genschöpf / Archetekt / Stromstart / Frigidtech
Media: MC
Released: 1982
Label & Cat. #:
Style: Electro / Avantgarde
Members: Max Fux keyb-voc, Vincenzo Marooni drums, Daniel Amiet guit-perc, Jimy (Mr. McGhetty)
bass-voc
Add. Info:
City / State: Bern / BE
See also:

Artist: G9
Title: Mor-Gen
Songs: Generatom / Glas Pinguin / X 4 / Princip / Kaltkult // Genschöpf / Archetekt / Stromstart / Frigidtech
Media: LP
Released: Januar 1983
Label & Cat. #: All Records – 01
Style: Electro / Avantgarde
Members: Max Fux keyb-voc, Vincenzo Marooni drums, Daniel Amiet guit-perc, Jymy (Mr. McGhetty)
bass-voc
Add. Info: Recorded fall 1982 in mono, includes infosheet.
City / State: Bern / BE
See also:

Artist: G9
Title: Antarktische Mädchen
Songs: Antarktische Mädchen // Glassee
Media: 7″
Released: 1984
Label & Cat. #: All Records 03
Style: Electro / Avantgarde
Members: Daniel Amiet guit-perc, Jymy (Mr. McGhetty) bass-voc, Vincenzo Marooni drums, Max Fux keyb-voc
Add. Info: Recorded in may 1983 at Red Mountain Studios, Bern. Cover art by Max Fux.
City / State: Bern / BE
See also:

Artist: G9
Title: Zukunft
Songs: Ouverture / Okkalt / Menschenmacher / Klar / Neuisland / Meta-All // Antarktische Mädchen
/ Auto-Psi / Glassee / Atomen / Geist Reise
Media: LP
Released: 1984
Label & Cat. #: Poplight PLR 5– GEN 1001
Style: Electro / Avantgarde
Members: Daniel Amiet guit-perc, Jymy (Mr.Mc Ghetty) bass-voc, Vincenzo Marconi drums-voc, Max Fux keyb-voc
Add. Info: Recorded in may 1983 at Red Mountain Studios, Bern. Cover art by Max Fux.
City / State: Bern / BE
See also:

Artist: G9
Title: The Magic-Show I Know 68-69
Songs: Intro- the End / Athma- Solar Plexus / Jllumi- The Axie // The Magic-Show I Know- The Live
Media: LP
Released: 1986
Label & Cat. #: Eigenproduktion Future Management MS 6886
Style: Electro / Avantgarde
Members: Daniel Amiet guit-perc, Jymy (Mr.Mc Ghetty) bass-voc, Vincenzo Marconi drums-voc, Max Fux keyb-voc
Add. Info: Cover art by H.P.Winkler.
City / State: Bern / BE
See also:

Artist: G9
Title: The Magic-Show I Know 68-69
Songs: Intro- the End / Athma- Solar Plexus / Jllumi- The Axie // The Magic-Show I Know- The Live
Media: LP
Released: 1986
Label & Cat. #: Eigenproduktion Future Management MS 6886
Style: Electro / Avantgarde
Members: Daniel Amiet guit-perc, Jymy (Mr.Mc Ghetty) bass-voc, Vincenzo Marconi drums-voc, Max Fux keyb-voc
Add. Info: Cover art by H.P.Winkler.
City / State: Bern / BE
See also:

Sampler max Collection 90-99

Artist: G9/You/TwinWizard
Title: Improver
Songs: MagiX / Lord of Darkness / Vision / White Magic / Japan / Zeitraum / Stärnä / Olemos Bruja / NowAge / Play Chess
Media: CD
Released: 1999
Label & Cat. #: Eigenproduktion kukuk-records
Style: Electro / Avantgarde-Rock
Members: Max Kleiner, You, TwinWizard, keyb-voc
Add. Info: Cover Portrait
City / State: Bern / BE
See also: TwinWizard Demo Tapes

G9
Im November 1980 wird G9 von MAX FUX und Vincenzo Marconi in Bern gegründet. Es folgten einige Konzerte experimenteller Art und im Sommer 81 wurde mit Jymy der Bassist gefunden. Danach wurde an einer eindrücklichen Licht und Ton Darbietung gearbeitet, mit der man im Zeitraum Ende 81/ Anfang 82 auf Tour ging. Licht-Neon-Ton-Mono-Bild-FUX Dias- Neon Ballet. Im November wurde mit Dany der perfekte Gitarrist und Percussionist gefunden. Im Herbst 82 wurde das Konzept Album Mor-Gen eingespielt, dass im Januar 1983 erschien.

Text Records:

  • 1981 Frigidarium – illustrierter Textband
  • 1982 Neonanie – Video S/W 40 min.
  • 1982 Mor-gen – LP Mono

In November 1980, G9 was founded by MAX FUX and Vincenzo Marconi in Bern. Several concerts of an experimental nature followed and in the summer of 81 Jymy, the bassist, was found. After that, an impressive light and sound performance was worked on, with which they went on tour in the period in late 81 / early 82. Light-Neon-Sound-Mono-Picture-FUX Dias- Neon Ballet. In November, the perfect guitarist and percussionist was found in Dany. In the autumn of 82 the concept album Mor-Gen was recorded that was released in January 83.

https://www.discogs.com/artist/1269862-G9

Swiss NDW/electro group, formed in November 1980 in Berne.
Members: Max Fux, Vincenzo Marconi, Daniel Amiet, Jymy (Mr. McGhetty)

Concert List

from Lurker , not finished yet 981

https://swisspunk.ch/

13. Dezember G9, Eigernordwand, Einsatz 117, Hecktick – Tscharni, Bern
(Soilant Productions)
Erstes Konzert?
31. Dezember G9 – Gaskessel, Biel

Ende 81/ Anfang 82 auf Tour ?

3 Gigs at the End of 82 in Esoterisches Centrum Amsterdam ?
Cause of Mono Pirate Radiostation o waven pratgen ?

1984
11. März G9 Turnhalle, Zentralschulhaus – Grüningen
13. Mai G9 – Rote Farbrik, Zürich
02. Juni G9 – ???, Brig
15. Juni G9 – Seminar Hofwil, Bern
21. Juni G9, Dead Boddy Moves, Spadder – Rote Fabrik, Zürich (Fabrik,
Liste?)
23. Juni G9 – ???, Birr

Overall Record History

1981 – Grauzone, LP Grauzone

1983 – G9, LP Mor-Gen

1984 – G9, LP Zukunft

1986 – G9, LP Magic Show

1991/93 – G9/You, Tape/CD Improver

https://sourceforge.net/projects/maxbox/files/maXbox_Archive/Improver/Improver_4_Edition_2021.zip/download

“Eisbär” (German for polar bear) is a 1980 “cult” song composed by the Swiss Neue Deutsche Welle band Grauzone. It first appeared on the 1980 compilation album Swiss Wave – The Album. The shorter single version was later collected on the Grauzone album Die Sunrise Tapes (1998) also with G9 Albums Mor-gen and Zukunft.

Sign of the 4 Elements – Fux Sign

ConTact

A more recent project is to reshape a song from 1975 with modern machine learning tunes, tones and tact.

Listen to the song (4 minutes)

https://drive.google.com/file/d/1bBbXx2PgeGTqAUkGcPWPTbLnRi3NH2ys/view?usp=sharing

The big machine guy at the end is canonically called Deus Ex Machina, literally “God out of the Machine,” a reference to the Greek theatrical practice of actually lowering the Greek gods onto stage with a crane.

Some Code for a Soft-Synthesizer:

const
  e1 = 2.71828182846;
  Start = -4.65;
  Intervallength = 1.0 - Start;

function ADSREnvelope(t,a,d,s,r,maxlevel,holdlevel:Single):Single;
//Hüllkurven Generator Attack-Decay-Sustain-Release Shape:
var iPos, x, delta : Single;
begin
  if t < 0 then begin
    Result:= 0;
    Exit;
  end;
  //Attack
  iPos:= a;
  if t < iPos then begin
    x:= 1.0 - t/a; //x between 0 und 1
    x:= x * Intervallength + Start; //x to map interval
    Result:= (1.0 - 1/e1*(Power(e1, x)))*maxlevel;
    Exit;
  end;
  //Decay
  iPos:= iPos + d;
  if t <= iPos then begin
    delta:= maxlevel - holdlevel;
    if delta <= 0.0 then begin
      Result:= holdlevel;
      Exit
    end;
    x:= 1.0 - (t - iPos + d)/d;
    x:= x * Intervallength + Start;
    Result:= Maxlevel - (1.0 - 1/e1*(Power(e1, x)))*delta;
    Exit;
  end;
  //Sustain
  iPos:= iPos + s;
  if t <= iPos then begin
    Result:= holdlevel;
    Exit
  end;
  //Release
  iPos:= iPos + r;
  if t <= iPos then begin
    x:= 1.0 - (t - iPos + r)/r;
    x:= x * Intervallength + Start;
    Result:= holdlevel-holdlevel*(1.0-1/e1*(Power(e1, x)));
    Exit;
  end;
  Result:= 0.0;
end;

Prophet

Rheingold

The Rheingold was a named train that operated between Hoek van Holland, near Rotterdam, and Geneva, Switzerland, a distance of 1,067 kilometres, until 1987. Another section of the train started in Amsterdam and was coupled to the Hoek cars in Utrecht.Wikipedia

BitBang One
Rheingold

Teaching Machine Learning

Pörtschach am Wörthersee Kärnten Österreich
EKON 26 Duesseldorf Schwan, Sternstrasse, Pempelfort, Duesseldorf, Germany, 8th November 2022

Build date 1973–1974 1803 Stored at Raeren, moved to Sokolov, Czech Republic in October 2011, scrapped in February 2012

MetaDefender API

V4 API is the latest version of MetaDefender Cloud API. It was designed to be fast, modular, easy to use and to provide seamless integration between MetaDefender API and MetaDefender Cloud API.

I will show how to call this API with several languages to SCAN a exe file.

File Overview

Vendor kleiner kommunikation Product maXbox4 Category E Copyright Free Pascal Script File type Executable File File Extension exe File size 28 MB [29608248 bytes] Uploaded 2020-06-16 17:02:33 [ 2 months ago ] Scanned 2020-08-28 18:51:29 [ 2 hours ago ] Duration a few seconds

MD5 21648AFA06BEAD05E50D20D8BC0B67D9

SHA1 DA4C716E31E2A4298013DFFBDA7A98D48650B0C7

SHA256 E0CB57D978207D09A6849EFB0E972FD4D0B407A42F6EB891AB41E68B53785293

First we start with Pascal in maXbox. We use type THTTPSend = class(TSynaClient) from the unit HTTPSend.

httpsend package
function HTTPMethod(const Method, URL: string): Boolean;

Connects to host define in URL and access to resource defined in URL by method. If Document is not empty, send it to server as part of HTTP request. Server response is in Document and headers. Connection may be authorized by username and password in URL. If you define proxy properties, connection is made by this proxy. If all OK, result is True, else result is False.

If you use in URL ‘https:’ instead only ‘http:’, then your request is made by SSL/TLS connection (if you not specify port, then port 443 is used instead standard port 80). If you use SSL/TLS request and you have defined HTTP proxy, then HTTP-tunnel mode is automaticly used .

property Headers: TStringList read FHeaders;

Before HTTP operation you may define any non-standard headers for HTTP request, except of: ‘Expect: 100-continue’, ‘Content-Length’, ‘Content-Type’, ‘Connection’, ‘Authorization’, ‘Proxy-Authorization’ and ‘Host’ headers. After HTTP operation contains full headers of returned document.

property Document: TMemoryStream read FDocument;

Stream with document to send (before request, or with document received from HTTP server (after request).

Const URL='https://api.metadefender.com/v4/file/bzIwMDYxNi1TSW42NDBPVlprTWw3YjRBMQ';
  
Begin  //@main

    srlist:= TStringlist.create;
    with THTTPSend.create() do begin
      Headers.Add('apikey: 6b337c92c792174a54acd715ab1aae64');      
      writeln(botostr(HTTPMethod('GET',URL))); 
      
      with TJson.create() do begin
        Parse(StreamtoString3(Document));
        Split(Stringify,'{',srlist)
      end;  

      writeln(itoa(resultCode)+':'+resultString+CRLF+srlist.text);
      clear;free;
    end;  
    srlist.Free;

    //with

Parent class of application protocol implementations. By this class is defined common properties.

Next we do the same with Python:

import requests

url = "https://api.metadefender.com/v4/file/bzIwMDYxNi1TSW42NDBPVnJJb0p1WTZWYTY"

headers = {
    'apikey': "6b337c92c792174a54acd715ab1aae64"
}

response = requests.request("GET", url, headers=headers)

print(response.text)

For a better understanding of the difference between V4 and previous versions of the API, see: V4 Migration guide.

Another solution is from Microsoft Windows HTTP Services (WinHTTP) which provides developers with an HTTP client application programming interface (API) to send requests through the HTTP protocol to other HTTP servers.
WinHTTP supports desktop client applications, Windows services, and Windows server-based applications.

// Instantiate a WinHttpRequest object.
   httpReq:= CreateOleObject('WinHttp.WinHttpRequest.5.1');

   // Open an HTTP connection.                
   hr:= httpReq.Open('GET', aURL, false);            
   if hr= 0 then 
       httpReq.setRequestheader('apikey','6b337c92c792174a54acd715ab1aae64'); 
    
   httpReq.Send()  /// Send HTTP Request & get Responses.
   writeln(httpReq.responseText)

   writeln(httpReq.GetAllResponseHeaders());         
   httpReq:= NULL;
   //close
Deprecation notice

All previous version of the API (V1, V2, and V3) will be deprecated in Feb 1st, 2020. Please make sure to update your code to use the latest version of the API. V4 will be supported for a minimum of 3 years since the date of its announcement (March 2019).

And in the last step with CURL:

curl 'https://api.metadefender.com/v4/file/bzIwMDYxNi1TSW42NDBPVnJJb0p1WTZWYTY' \
    -H 'apikey: 6b337c92c792174a54acd715ab1aae64'
Class THTTPSend 

Functions and Procedures

function HttpGetText(const URL: string; const Response: TStrings): Boolean;
function HttpGetBinary(const URL: string; const Response: TStream): Boolean;
function HttpPostBinary(const URL: string; const Data: TStream): Boolean;
function HttpPostURL(const URL,URLData: string; const Data: TStream): Boolean;
function HttpPostFile(const URL,FieldName,FileName: string; const Data: TStream; const ResultData: TStrings): Boolean;

Note: The apikey is used for all API request to MetaDefender Cloud service. A Web Request or SendRequest can pass a request header to do that and control the response header too, for example the X-Authenticated: by apikey :

1.0 HTTP/1.1 200 OK
Date: Sat, 29 Aug 2020 10:39:58 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 5294
Connection: keep-alive
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Vary: Accept-Encoding, Origin
X-Authenticated: by apikey
X-Account-Type: anonymous
X-Content-Type-Options: nosniff
ETag: “14ae-6IDbUoWEYrVD4MsFYbhiMMsZWIM”
X-Response-Time: 648ms

From Res Stauffer
Machine Learning Language Detection
TEE Goethe
Silvi’s Day

ADO Connect

TADOConnection encapsulates the ADO connection object. Use TADOConnection for connecting to ADO data stores. The connection provided by a single TADOConnection component can be shared by multiple ADO command and dataset components through their Connection properties.

Create an Access database and table Using ADOX:

function CreateAccessDatabase(aFileName: string): string;
var cat: OLEVariant;
begin
  Result:= '';
  try
    cat:= CreateOleObject('ADOX.Catalog');
    cat.Create('Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + aFileName + ';');
    cat:= NULL;
  except
    writeln(ExceptionToString(ExceptionType, ExceptionParam));
    writeln('ADOX.Catalog create failed ');
    //on e: Exception do Result := e.message;
  end;
end;

You call the Create with

Const MYPATH2 ='C:\maXbox\mX47464\maxbox4\examples\maxbase4runtimedb6.mdb';

CreateAccessDatabase(MYPATH2)

ADOX is an extension to ADO that lets you create and modify database structures (tables and fields). It was created specifically for working with the Jet database engine. According to Microsoft, you might have problems using it with other database engines.

Now we create a table with ADO Connect and SQL:

Const MyPath2 ='C:\maXbox\mX47464\maxbox4\examples\maxbase4runtimedb6.mdb';

procedure CreateAccessTable(Sender: TObject; 
             ADOConnection11: TADOConnection; ADOCommand11: TADOCommand);
 var MYDb: TADOConnection; 
     ADOCommand1: TADOCommand;
begin
  MyDb:= TADOConnection.Create(Self);
  MyDb.Close;
  //Provider=MSDASQL.1;Persist Security Info=False;Data Source=database3
  MyDb.ConnectionString:= 'Provider=Microsoft.Jet.OLEDB.4.0;' +
                           'Data Source=' + MyPath2 + ';' +
                           'Persist Security Info=True;';
  MyDb.LoginPrompt:=False;
  MyDb.Connected:= True;
  MyDb.BeginTrans;
  ADOCommand1:= TADOCommand.create(self)
  try
    ADOCommand1.connection:=  MyDb;
    ADOCommand1.CommandText:= 'CREATE TABLE TABLE1 ('
                               +'ID AUTOINCREMENT,'
                               +'FirstName varchar(255) NOT NULL,'
                               +'LastName varchar(255),'
                               +'Age int )';                                         
                                          
    ADOCommand1.Execute;
    MyDb.CommitTrans;
    ADOCommand1.Free;
  except
    MyDb.RollbackTrans;
    writeln(ExceptionToString(ExceptionType, ExceptionParam));
    //Exception: Syntax error in CONSTRAINT clause
    ShowmessageBig('CREATE Table Exception');
  end;  
end;  

TADOConnection allows you to control the attributes and conditions of a connection to a data store. Use the properties of TADOConnection to control such attributes as record locking scheme (optimistic versus pessimistic), cursor type, cursor location, isolation level, and connection time-out. Methods are also provided for implementing transactions and retrieving metadata about the database to which this component connects.

However, it is useful for creating tables and fields because you can easily define data types and indexes (which you cannot do in ADO).

At least we fill the table with a few records and do a Query to show the result:

procedure InsertADORecordClick(Sender: TObject; 
             ADOConnection1: TADOConnection; ADOCommand1: TADOCommand);
begin
  ADOConnection1.BeginTrans;
  ADOCommand1:= TADOCommand.create(self)
  try
    ADOCommand1.connection:= ADOConnection1;
    ADOCommand1.CommandText:= 'INSERT INTO Table1 (FirstName, LastName, Age) '
                               +'VALUES (''Max'',''Box4'', 69)';                           
    ADOCommand1.Execute;
    ADOConnection1.CommitTrans;
    ADOCommand1.Free;
  except
    ADOConnection1.RollbackTrans;
    writeln(ExceptionToString(ExceptionType, ExceptionParam));
    ShowmessageBig('INSERT Exception');
  end;  
end;  

procedure QueryADOSet(AdoConnection: TAdoConnection);
var AdoQuery: TADOQuery;
begin
   AdoQuery:= TADOQuery.Create(nil);
   try
    AdoQuery.Connection:=AdoConnection;
    AdoQuery.SQL.Add('SELECT * FROM Table1');
    AdoQuery.Open;
    while not  AdoQuery.EOF do begin
      //Writeln(AdoQuery.FieldByname('LastName').AsString);
      Write(AdoQuery.Fields[2].AsString+': ');
      AdoQuery.Next;
    end;
   finally
   AdoQuery.Free;
   end;
end;  

In the end we can test it on the SQL ADO Workbench integrated as add-on in maXbox:

Strange Circles

The use of prior time steps to predict the next time step is called the sliding window method. For short, it may be called the window method in some literature. In statistics and time series analysis, this is called a lag or lag method.

SMI 10 Years 2010-2020

The number of previous time steps is called the window width or size of the lag.

This sliding window is the basis for how we can turn any time series dataset into a supervised learning problem. From this simple example, we can notice a few things:

We can see how this can work to turn a time series into either a regression or a classification supervised learning problem for real-valued or labeled time series values.
We can see how once a time series dataset is prepared this way that any of the standard linear and nonlinear machine learning algorithms may be applied, as long as the order of the rows is preserved.

We can see how the width sliding window can be increased to include more previous time steps.
We can see how the sliding window approach can be used on a time series that has more than one value, or so-called multivariate time series.

https://machinelearningmastery.com/time-series-forecasting-supervised-learning/
>>> import pandas_datareader.data as web
>>> df= web.DataReader('^SSMI', data_source='yahoo',start='09-11-2010')

from sklearn.preprocessing import LabelEncoder 
labelencoder= LabelEncoder() #initializing an object of class LabelEncoder
data['C'] = labelencoder.fit_transform(data['C']) #fitting and transforming the desired categorical column.
df.loc[(df!=0).any(axis=1)]
df= df[df['ColName'] != 0]
>>> df['Date'] = pd.to_datetime(df.index)

>>> df['Date'] = pd.to_datetime(df.index)
>>> df.info()
Name: day, Length: 1217, dtype: int64
>>> df['weekday'] = pd.DatetimeIndex(df['Date']).weekday
>>> df.corr()
               High       Low      Open  ...         C       day   weekday
High       1.000000  0.998770  0.999482  ...  0.976134 -0.020020  0.002322
Low        0.998770  1.000000  0.999033  ...  0.974153 -0.020093  0.001344
Open       0.999482  0.999033  1.000000  ...  0.974553 -0.018877  0.003661
Close      0.999244  0.999400  0.998730  ...  0.975822 -0.020204  0.001031
Volume    -0.123889 -0.148456 -0.131867  ... -0.117059  0.015028  0.185688
>>> plt.scatter(df.Volume,df.weekday)
<matplotlib.collections.PathCollection object at 0x0000001258226AC8>
>>> plt.show()
import pandas_datareader.data as web
df= web.DataReader('^SSMI', data_source='yahoo',start='09-11-2010')
#quotes = quotes_historical_yahoo_ochl("INTC", 
#        datetime.date(1994, 4, 5), datetime.date(2015, 7, 3))

quotes = df
print(quotes.info(5))

x_ax_time = range(len(df))
plt.plot(x_ax_time, quotes['Close'])
plt.show()

# Extract the required values
# ValueError: invalid literal for int() with base 10: 'H'
# dates = np.array([quote[0] for quote in quotes], dtype=np.int)
dates = quotes.index
#closing_values = np.array([quote[3] for quote in quotes])
#volume_of_shares = np.array([quote[5] for quote in quotes])[1:]
closing_values = np.array(quotes['Close'])
volume_of_shares = np.array(quotes['Volume'])

# Take diff of closing values and computing rate of change
diff_percentage = 100.0 * np.diff(closing_values) / closing_values[:-1]
dates = dates[1:]

# ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 0, 
# the array at index 0 has size 2488 and the array at index 1 has size 2489
# Stack the percentage diff and volume values column-wise for training
Xm = np.column_stack([diff_percentage, volume_of_shares[1:]])

# Create and train Gaussian HMM 
print ("\nTraining HMM....& Plot")
hmm_model = GaussianHMM(n_components=3, covariance_type="diag", n_iter=1000)
hmm_model.fit(Xm)
y_pred = hmm_model.predict(Xm)

print("Model Score:", hmm_model.score(Xm))
 # Plot the in sample hidden states closing values
Xm2 = np.column_stack([diff_percentage[1:], volume_of_shares[2:]]) 
#hmm_model.fit(Xm2)
plot_in_sample_hidden_states(hmm_model, quotes[2:], Xm2)

# Generate data using model
# https://www.quantstart.com/articles/market-regime-detection-using-hidden-markov-models-in-qstrader/

num_samples = 500 
samples, _ = hmm_model.sample(num_samples) 
plt.plot(np.arange(num_samples), samples[:,0], c='black')

plt.show()

 @staticmethod
    def _extract_features(data):
        open_price = np.array(data['open'])
        close_price = np.array(data['close'])
        high_price = np.array(data['high'])
        low_price = np.array(data['low'])
 
        # Compute fraction change in close, high and low prices
        # which would be used a feature
        frac_change = (close_price - open_price) / open_price
        frac_high = (high_price - open_price) / open_price
        frac_low = (open_price - low_price) / open_price
 
        return np.column_stack((frac_change,frac_high,frac_low))
        # ret

procedure TPaintForm1Timer1Timer(Sender: TObject);
var i : real;
  x1,x2,y1,y2 : integer;
begin
  straal:=straal+3;
  if straal>500 then straal:=0;
  repeat
    r:=r+16;
    if r>255 then
      r:=0;
    g:=g+13;
    if g>255 then
      g:=0;
    b:=b+10;
    if b>255 then
      b:=0;
    i:=i+pi/65;
    x1:=Round(Sin(i)*straal);
    y1:=Round(Cos(i)*straal);
    x2:=Round(Sin(i)*straal+20);
    y2:=Round(Cos(i)*straal+20);
    Paintbox1.Canvas.Pen.Style:=psclear;
    Paintbox1.Canvas.Brush.Color:=RGB(r,g,b);
    Paintbox1.Canvas.Ellipse(400+x1,300+y1,400+x2,300+y2);
  until i>=2*pi;
end;

In a Hidden Markov Model (HMM), we have an invisible Markov chain (which we cannot observe), and each state generates in random one out of k observations, which are visible to us. Let’s look at an example of the SMI Chart over 10 years above.

#sign:max: MAXBOX8: 13/03/2019 07:46:37
# optimal moving average OMA for market index signals - max kleiner
 
import numpy as np
import matplotlib.pyplot as plt
from sklearn import tree
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

# [volume, weight_index, call_put_ratio]
X = [[181, 80, 44], [177, 70, 43], [160, 60, 38], [154, 54, 37], [166, 65, 40],
     [190, 90, 47], [175, 64, 39],
     [177, 70, 40], [159, 55, 37], [171, 75, 42], [181, 85, 43], [168, 75, 41], [168, 77, 41]]

Y = ['buy', 'buy', 'sell', 'sell', 'buy', 'buy', 'sell', 'sell',
     'sell', 'buy', 'buy', 'sell', 'sell']

test_data = [[190, 70, 43],[154, 75, 42],[181,65,40]]
test_labels = ['buy','buy','buy']

#DecisionTreeClassifier
dtc_clf = tree.DecisionTreeClassifier()
dtc_clf = dtc_clf.fit(X,Y)
dtc_prediction = dtc_clf.predict(test_data)
print (dtc_prediction)

#RandomForestClassifier
rfc_clf = RandomForestClassifier()
rfc_clf.fit(X,Y)
rfc_prediction = rfc_clf.predict(test_data)
print (rfc_prediction)

#Support Vector Classifier
s_clf = SVC(gamma='auto', C=0.1, kernel='linear')
s_clf.fit(X,Y)
s_prediction = s_clf.predict(test_data)
print (s_prediction)


#LogisticRegression
l_clf = LogisticRegression(solver='liblinear')
l_clf.fit(X,Y)
l_prediction = l_clf.predict(test_data)
print (l_prediction)

#accuracy scores
dtc_tree_acc = accuracy_score(dtc_prediction,test_labels)
rfc_acc = accuracy_score(rfc_prediction,test_labels)
l_acc = accuracy_score(l_prediction,test_labels)
s_acc = accuracy_score(s_prediction,test_labels)

classifiers = ['Decision Tree', 'Random Forest', 'Logistic Regression' , 'SVC']
accuracy = np.array([dtc_tree_acc, rfc_acc, l_acc, s_acc])
max_acc = np.argmax(accuracy)
print(classifiers[max_acc] + ' is the best classifier for this problem')
print(dtc_tree_acc, rfc_acc, l_acc,s_acc) 

# Get quotes from Yahoo finance and find optimal moving average

import pandas_datareader.data as web
df= web.DataReader('^SSMI', data_source='yahoo',start='09-11-2010')

#DataMax - Predict for 30 days; Predicted has the data of Adj. Close shifted up by 30 rows
forecast_len=60  #oma is 5

quotes = df
print(quotes.info(5))

df['_SMI_20'] = df.iloc[:,3].rolling(window=20).mean()
df['_SMI_60'] = df.iloc[:,3].rolling(window=forecast_len).mean()
df['_SMI_180'] = df.iloc[:,3].rolling(window=160).mean()

x_ax_time = quotes.index #range(len(df))
plt.figure(figsize=[12,8])
plt.grid(True)
plt.title('Optimal Moving Average OMA', fontsize=18)
plt.plot(x_ax_time, quotes['Close'], label='Close')
plt.plot(x_ax_time, df['_SMI_60'],label='MA 3 Month')
plt.plot(x_ax_time, df['_SMI_180'],label='MA 9 Month')
#plt.xlabel('days', fontsize=15)
# plt.plot_date(quotes.index, quotes['Close'])
plt.legend(loc=2)
plt.show()

dates = quotes.index
dates = dates[1:]
#closing_values = np.array([quote[3] for quote in quotes])
#volume_of_shares = np.array([quote[5] for quote in quotes])[1:]
closing_values = np.array(quotes['Close'])
volume_of_shares = np.array(quotes['Volume'])

#Predict for 30 days; Predicted has the data of Close shifted up by 30 rows

ytarget = quotes['Close'].shift(-forecast_len)
ytarget= ytarget[:-forecast_len]
Xdata= closing_values[:-forecast_len]

from sklearn.svm import SVR
# Split datasets into training and test sets (80% and 20%)
print('shape len2: ',len(ytarget),len(Xdata))
x_train,x_test,y_train,y_test=train_test_split(Xdata,ytarget,test_size=0.2, \   random_state= 72)
print('shape len3: ',len(x_train),len(y_train))

# - Create SVR model and train it
svr_rbf=SVR(kernel='rbf',C=1e3,gamma=0.1) 
x_train = x_train.reshape(-1,1)
svr_rbf.fit(x_train,y_train)

#DBASTAr - Get score
svr_rbf_confidence=svr_rbf.score(x_test.reshape(-1,1),y_test)
print(f"SVR Confidence: {round(svr_rbf_confidence*100,2)}%")


""""   Column     Non-Null Count  Dtype
---  ------     --------------  -----
 0   High       2500 non-null   float64
 1   Low        2500 non-null   float64
 2   Open       2500 non-null   float64
 3   Close      2500 non-null   float64
 4   Volume     2500 non-null   int64
 5   Adj Close  2500 non-null   float64
dtypes: float64(5), int64(1)
memory usage: 136.7 KB
"""


#sign:max: MAXBOX8: 07/09/2020 07:46:37
# optimal moving average OMA for market index signals - max kleiner
# v2 shell argument forecast days - 4 lines compare - ^GDAXI for DAX
# pip install pandas-datareader
 
import numpy as np
import matplotlib.pyplot as plt
import sys
from sklearn import tree
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

# [volume, weight_index, call_put_ratio]
X = [[181, 80, 44],[177, 70, 43],[160, 60, 38],[154, 54, 37],[166, 65, 40],
     [190, 90, 47],[175, 64, 39],
     [177, 70, 40],[159, 55, 37],[171, 75, 42],[181, 85, 43],[168, 75, 41],[168, 77, 41]]

Y = ['buy', 'buy', 'sell', 'sell', 'buy', 'buy', 'sell', 'sell',
     'sell', 'buy', 'buy', 'sell', 'sell']

test_data = [[190, 70, 43],[154, 75, 42],[181,65,40]]
test_labels = ['buy','buy','buy']

#DecisionTreeClassifier
dtc_clf = tree.DecisionTreeClassifier()
dtc_clf = dtc_clf.fit(X,Y)
dtc_prediction = dtc_clf.predict(test_data)
print (dtc_prediction)

#RandomForestClassifier
rfc_clf = RandomForestClassifier()
rfc_clf.fit(X,Y)
rfc_prediction = rfc_clf.predict(test_data)
print (rfc_prediction)

#Support Vector Classifier
s_clf = SVC(gamma='auto', C=0.1, kernel='linear')
s_clf.fit(X,Y)
s_prediction = s_clf.predict(test_data)
print (s_prediction)

#LogisticRegression
l_clf = LogisticRegression(solver='liblinear')
l_clf.fit(X,Y)
l_prediction = l_clf.predict(test_data)
print (l_prediction)

#accuracy scores
dtc_tree_acc = accuracy_score(dtc_prediction,test_labels)
rfc_acc = accuracy_score(rfc_prediction,test_labels)
l_acc = accuracy_score(l_prediction,test_labels)
s_acc = accuracy_score(s_prediction,test_labels)

classifiers = ['Decision Tree', 'Random Forest', 'Logistic Regression' , 'SVC']
accuracy = np.array([dtc_tree_acc, rfc_acc, l_acc, s_acc])
max_acc = np.argmax(accuracy)
print(classifiers[max_acc] + ' is the best classifier for this problem')
print(dtc_tree_acc, rfc_acc, l_acc,s_acc) 

# Quotes from Yahoo finance and find optimal moving average
import pandas_datareader.data as web

#DataMax - Predict for 30 days; Predicted has the data of Adj. Close shifted up by 30 rows
forecast_len=80  #default oma is 5
YQUOTES = '^SSMI'
PLOT = 'Y'
try:
  forecast_len = int(sys.argv[1])
  #forecast_len= int(' '.join(sys.argv[1:]))
  YQUOTES = str(sys.argv[2])
  PLOT = str(sys.argv[3])
except:
  forecast_len= forecast_len
  YQUOTES = YQUOTES
  
#YQUOTES = 'BTC-USD'  #^GDAXI' , '^SSMI' , '^GSPC' (S&P 500 ) - ticker='GOOGL'
try:
  df= web.DataReader(YQUOTES, data_source='yahoo',start='09-11-2010')  
except:
  YQUOTES = '^SSMI'
  df= web.DataReader(YQUOTES, data_source='yahoo',start='09-11-2010')
  print('Invalid Quote Symbol got ^SSMI instead')
      
#data = ' '.join(sys.argv[1:])
print ('get forecast len:',forecast_len, 'for ', YQUOTES)
quotes = df
print(quotes.info(5))
print(quotes['Close'][:5])
print(quotes['Close'][-3:])
df['_SMI_20'] = df.iloc[:,3].rolling(window=20).mean()
df['_SMI_60'] = df.iloc[:,3].rolling(window=60).mean()
df['_SMI_180'] = df.iloc[:,3].rolling(window=180).mean()
df['_SMI_OMA'] = df.iloc[:,3].rolling(window=forecast_len).mean()

#"""
if PLOT=='Y':
   x_ax_time = quotes.index #range(len(df))
   plt.figure(figsize=[12,7])
   plt.grid(True)
   plt.title('Optimal Moving Average OMA: '+YQUOTES, fontsize=18)
   plt.plot(x_ax_time, quotes['Close'], label='Close')
   plt.plot(x_ax_time, df['_SMI_60'],label='MA 3 Month')
   plt.plot(x_ax_time, df['_SMI_180'],label='MA 9 Month')
   plt.plot(x_ax_time, df['_SMI_OMA'],label='OMA '+str(forecast_len)+' D.')
   #plt.xlabel('days', fontsize=15)
   # plt.plot_date(quotes.index, quotes['Close'])
   plt.legend(loc=2)
   plt.show()
#"""

dates = quotes.index
dates = dates[1:]
#closing_values = np.array([quote[3] for quote in quotes])
#volume_of_shares = np.array([quote[5] for quote in quotes])[1:]
closing_values = np.array(quotes['Close'])
volume_of_shares = np.array(quotes['Volume'])

#Predict for 30 days; Predicted has the Quotes of Close shifted up by 30 rows
ytarget= quotes['Close'].shift(-forecast_len)
ytarget= ytarget[:-forecast_len]
Xdata= closing_values[:-forecast_len]
#print('Offset shift:',ytarget[:10])

# Feature Scaling
#sc_X = StandardScaler()
#sc_y = StandardScaler()
#Xdata = sc_X.fit_transform(Xdata.reshape(-1,1))
#You need to do this is that pandas Series objects are by design one dimensional.
#ytarget = sc_y.fit_transform(ytarget.values.reshape(-1,1))

from sklearn.svm import SVR
# Split datasets into training and test sets (80% and 20%)
print('target shape len2: ',len(ytarget),len(Xdata))
x_train,x_test,y_train,y_test=train_test_split(Xdata,ytarget,test_size=0.2, \
                                                       random_state= 72)
print('xtrain shape len3: ',len(x_train),len(y_train))

# - Create SVR model and train it
svr_rbf= SVR(kernel='rbf',C=1e3,gamma=0.1) 
x_train = x_train.reshape(-1,1)
svr_rbf.fit(x_train,y_train)

# Predicting single value as new result
print('predict old in :', forecast_len, svr_rbf.predict([quotes['Close'][:1]]))
print('predict now in :', forecast_len, svr_rbf.predict([quotes['Close'][-1:]]))

#DBASTAr - Get score
svr_rbf_confidence=svr_rbf.score(x_test.reshape(-1,1),y_test)
print(f"SVR Confidence: {round(svr_rbf_confidence*100,2)}%")


""""   Column     Non-Null Count  Dtype
---  ------     --------------  -----
 0   High       2500 non-null   float64
 1   Low        2500 non-null   float64
 2   Open       2500 non-null   float64
 3   Close      2500 non-null   float64
 4   Volume     2500 non-null   int64
 5   Adj Close  2500 non-null   float64
dtypes: float64(5), int64(1)
memory usage: 136.7 KB
df.index = pd.to_datetime(df.index)
"""


So I had to find out the optimal moving average within a loop from about 20 to 50 days to get a high confidence score in steps of 5 days interval:

memory usage: 137.1 KB
None
Date
2010-09-13 6471.770020
2010-09-14 6466.319824
2010-09-15 6434.009766
2010-09-16 6424.160156
2010-09-17 6389.020020
Name: Close, dtype: float64
Date
2020-09-04 10153.089844
2020-09-07 10297.799805
2020-09-08 10261.019531
Name: Close, dtype: float64
target shape len2: 2457 2457
xtrain shape len3: 1965 1965
predict old in : 50 [6532.54014764]
predict now in : 50 [8599.34565955]
SVR Confidence: 68.28%

Serie 50 : 68.28%

List of 20-50 days so according to the score 25 days would be best:
20 – 69.05%
25 – 70.04%
30 – 67.8%
35 – 67.04%
40 – 67.74%
45 – 68.07%
50 – 68.28%

begin //@main

  saveString(exepath+'mygauss.py',ACTIVESCRIPT);
  sleep(200)
  //if fileExists(PYPATH+'python.exe') then 
   if fileExists(PYSCRIPT) then begin

     //ShellExecute3('cmd','/k '+PYPATH+'python.exe '+PYCode+ ' '+
     //                       PYFILE ,secmdopen);
     //ShellExecute3('cmd','/k '+PYPATH+'python.exe && '+PYFILE +'&& mygauss3()'
     //                                  ,secmdopen);
      { ShellExecute3('cmd','/k '+PYPATH+
                        'python.exe && exec(open('+exepath+'mygauss.py'').read())'
                        ,secmdopen);
                 }       
 
     { ShellExecute3('cmd','/k '+PYPATH+
                        'python.exe '+exepath+'mygauss.py', secmdopen); }
     // ShellExecute3(PYPATH+'python.exe ',exepath+'mygauss.py'
     //                   ,secmdopen);
     maxform1.console1click(self);
     memo2.height:= 205;
     // maxform1.shellstyle1click(self);
     // writeln(GetDosOutput(PYPATH+'python.exe '+PYSCRIPT,'C:\'));
    fcast:= 75;
    olist:= TStringlist.create;
    GetDosOutput('py '+PYSCRIPT+' '+itoa(fcast)+' "^SSMI" "Y"','C:\');
    for it:= 20 to 50 do 
       if it mod 5=0 then begin
         //writeln(GetDosOutput('py '+PYSCRIPT+' '+itoa(it)+' "BTC-USD"'+ ' N','C:\'));
         dosout:= GetDosOutput('py '+PYSCRIPT+' '+itoa(it)+' "^SSMI" "N"','C:\');
         writeln(dosout)
         with TRegExpr.Create do begin
            Expression:=('SVR Confidence: ([0-9\.%]+).*');
            if Exec(dosout) then begin
              PrintF('Serie %d  : %s', [it, Match[1]]);
              olist.add(itoa(it) + ' - '+Match[1])
            end;   
          Free;
         end; 
       end;   
     writeln(olist.text)
     olist.Free;  
     // writeln(GetDosOutput('dir *.*','C:\'));
   end;
End.

A Use Case with the OMA Model and Bitcoin. Lets find the Opimal Moving Average with a SVR (Epsilon-Support Vector Regression).

The free parameters in the model are C and epsilon.

The implementation is based on libsvm. The fit time complexity is more than quadratic with the number of samples which makes it hard to scale to datasets with more than a couple of 10000 samples (we do have 2185 entries).

Get forecast len: from 20 to 130 for BTC-USD

DatetimeIndex: 2185 entries, 2014-09-16 to 2020-09-10
Data columns (total 6 columns):
# Column Non-Null Count Dtype
— —— ————– —–
0 High 2185 non-null float64
1 Low 2185 non-null float64
2 Open 2185 non-null float64
3 Close 2185 non-null float64
4 Volume 2185 non-null float64
5 Adj Close 2185 non-null float64
dtypes: float64(6)
memory usage: 119.5 KB
None
Date
2014-09-16 457.334015
2014-09-17 424.440002
2014-09-18 394.795990
2014-09-19 408.903992
2014-09-20 398.821014
Name: Close, dtype: float64
Date
2020-09-07 10131.516602
2020-09-08 10242.347656
2020-09-10 10296.268555
Name: Close, dtype: float64
target shape len2: 2055 2055
xtrain shape len3: 1644 1644
predict old in : 130 [596.1518452]
predict now in : 130 [5843.31880494]
SVR Confidence: 59.75%

We loop from 20 to 130 to find the max confidence score:

   QuoteSymbol:= 'BTC-USD'; //'BTC-USD'; //^SSMI    TSLA
    olist:= TStringlist.create;
    olist.NameValueSeparator:= '=';
    //olist.Sorted:= True;
    //olist.CustomSort(@CompareFileName)
    //GetDosOutput('py '+PYSCRIPT+' '+itoa(fcast)+' '+QuoteSymbol+' "Y"','C:\');
    GetDosOutput('py '+RUNSCRIPT+' '+itoa(fcast)+' '+QuoteSymbol+' "Y"','C:\');
  
    for it:= 20 to 130 do 
       if it mod 5=0 then begin
         //(GetDosOutput('py '+PYSCRIPT+' '+itoa(it)+' "BTC-USD"'+ 'Plot?','C:\'));
         dosout:= GetDosOutput('py '+RUNSCRIPT+' '+itoa(it)+' '+QuoteSymbol+' "N"','C:\');  
         writeln(dosout)
         with TRegExpr.Create do begin
            //Expression:=('SVR Confidence: ([0-9\.%]+).*');
            Expression:=('SVR Confidence: ([0-9\.]+).*');
            if Exec(dosout) then begin
              PrintF('Serie %d  : %s',[it, Match[1]]);
              olist.add(Match[1]+'='+itoa(it));
              Yvalfloat[it]:= strtofloat(Copy(match[1],1,5));  
              //MaxFloatArray           
            end;
          Free;
         end; 
       end;   
     writeln(CR+LF+olist.text)
     writeln('OMA from key value list2: '+floattostr(MaxFloatArray(Yvalfloat)))
     TheMaxOMA:= olist.Values[floattostr(MaxFloatArray(Yvalfloat))];
     writeln('OMA for Chart Signal: '+TheMaxOMA);
     olist.Free;  
    (GetDosOutput('py '+RUNSCRIPT+' '+(TheMaxOMA)+' '+QuoteSymbol+' "Y"','C:\'));
   end;

56.9=20
59.04=25
55.73=30
55.86=35
56.87=40
57.71=45
54.23=50
57.08=55
59.64=60
52.66=65
56.68=70
57.06=75
59.75=80
55.68=85
60.32=90
59.43=95
61.42=100
58.69=105
65.31=110
62.47=115
61.89=120
62.35=125
59.75=130

OMA from key value list2: 65.31
OMA for Chart Signal: 110

bitcoin chart

So the close line (blue) cuts the OMA (redline) from up to down and thats our next sell-signal:

Another maXbox Build

Computer software consists of a series of instructions in the programming language Object Pascal; the coder complies those statements into a form that a computer processor can understand. Building software requires knowledge of computer languages, syntax, machine environment and logic to complete the process from start to finish.

Try it online!

The version maXbox 4.7.4.64 has the following increment changes:

14/06/2020 16:06 83,362 623_exspawnu_buffoverflow_makecert4secure_sign_maxbox.pas
14/06/2020 22:23 17,652 694_OverbyteIcsAsn1Utils.pas
14/06/2020 22:53 44,491 705_new_classes_demoapp_wmi_60.pas
14/06/2020 22:25 33,543 712_towerofhanoi_animation_test.pas
14/06/2020 22:24 480,639 729_U_BigIntTest_mX4.pas
14/06/2020 17:35 66,769 965_RSA_IBZ_PrivatePublicKey_Form3p.pas
14/06/2020 17:18 57,924 966_U_PointInSpace52_mX4Form2.pas
14/06/2020 19:41 70,816 970_U_Decrypt4Forms22.pas
14/06/2020 19:42 9,121 972_U_HashedWordCount.pas
14/06/2020 18:02 28,760 970_U_ScrambledPiemX4Forms.pas
14/06/2020 13:04 3,195 U_Invertedtext.pas
14/06/2020 11:11 8,602 uPSI_HashUnit.pas
14/06/2020 13:03 2,807 uPSI_U_Invertedtext.pas
14/06/2020 14:33 406,742 fMain.pas
14/06/2020 20:22 27,406 752_U_ConvertTest2Astronomy_Bern.pas
14/06/2020 20:27 12,998 814_FANN_XorSample2.pas
14/06/2020 17:58 35,635 652_graph3DMainUnit2.pas
14/06/2020 14:33 406,742 fMain.pas
14/06/2020 12:45 21,823 bricks.pas
14/06/2020 14:14 40,921 Jsons.pas
14/06/2020 14:18 18,431 JsonsUtilsEx.pas
14/06/2020 11:19 4,968 lifeblocks.pas
14/06/2020 12:21 53,959 uPSI_Bricks.pas
14/06/2020 17:15 39,572 uPSI_Jsons.pas
14/06/2020 13:58 10,514 uPSI_lifeblocks.pas
14/06/2020 15:06 118,580 uPSI_PsAPI.pas

Building computer software requires the proper tools, an understanding of a computer language and the ability to think logically. Software operates with hard logical constraints with no gray areas; the computer processor will not guess or make decisions on its own. Then I got the following compilded units:

4/06/2020 13:49 16,833 FindReplDlg.dcu
14/06/2020 14:36 468,456 fMain.dcu
14/06/2020 13:49 35,172 gsUtils.dcu
14/06/2020 13:49 190,525 IFSI_WinForm1puzzle.dcu
14/06/2020 13:49 145,471 uPSI_fMain.dcu
14/06/2020 13:49 10,780 uPSI_IdPOP3.dcu
14/06/2020 13:49 5,647 uPSI_JvParsing.dcu
14/06/2020 13:49 20,800 uPSI_uTPLb_AES.dcu
14/06/2020 13:49 25,471 VListView.dcu
14/06/2020 13:49 70,840 WinForm1.dcu
14/06/2020 13:49 105,324 AdoMain.dcu
14/06/2020 12:54 31,086 Bricks.dcu
14/06/2020 13:49 11,792 frmExportMain.dcu
14/06/2020 14:18 45,913 Jsons.dcu
14/06/2020 14:18 15,350 JsonsUtilsEx.dcu
14/06/2020 12:02 6,035 lifeblocks.dcu
14/06/2020 15:44 30,819 MathsLib.dcu
14/06/2020 14:49 6,566 PXLTiming.dcu
14/06/2020 13:49 3,879 simplecomport.dcu
14/06/2020 12:21 41,950 uPSI_Bricks.dcu
14/06/2020 13:49 16,019 uPSI_DFFUtils.dcu
14/06/2020 15:42 35,944 uPSI_Jsons.dcu
14/06/2020 14:06 9,208 uPSI_lifeblocks.dcu
14/06/2020 15:34 101,316 uPSI_PsAPI.dcu
14/06/2020 14:49 8,645 uPSI_PXLTiming.dcu
14/06/2020 13:49 19,482 ViewToDoFm.dcu
14/06/2020 11:15 40,890 OverbyteIcsMimeUtils.dcu
14/06/2020 14:49 77,139 OverbyteIcsUtils.dcu
13/06/2020 23:19 34,699 JvXPCore.dcu

The most important tool the programmer must select to build software is the compiler. Modern development environments combine all of the software tools needed to develop a program into a single suite. Further changes are listed in the Subversion System of sourceforge:

— v5
+++ v6
@@ -1,5 +1,5 @@
*********
-Release Notes maXbox 4.7.4.62 June 2020 mX47
+Release Notes maXbox 4.7.4.64 June 2020 mX47
*********

1254 unit uPSI_MaskEdit.pas FCL
@@ -21,13 +21,19 @@
1270 uPSI_USearchAnagrams.pas DFF
1271 uPSI_JsonsUtilsEx.pas Randolph
1272 unit uPSI_Jsons.pas Randolph
+1273 unit uPSI_HashUnit; DFF
+1274 uPSI_U_Invertedtext.pas DFF
+1275 unit uPSI_Bricks; Dendron
+1276 unit uPSI_lifeblocks.pas Dendron

-Totals of Function Calls: 32614
-SHA1: of 4.7.4.62 BCE03C310FAEBA451DF2BDEE7B3A0DE2B5ECB8BD
-CRC32: 90312EBE: 28.1 MB (29,532,472) bytes
+Totals of Function Calls: 32633
+SHA1: of 4.7.4.64 DA4C716E31E2A4298013DFFBDA7A98D48650B0C7
+CRC32: 3EB27A87: 28.2 MB (29,608,248) bytes

Bugfix: Pagecontrol, TTabcontrol with onchange event TTabChangingEvent, TGetSiteInfoEvent,
TCheckListBox.Style Property TListBoxStyle Enumeration
glsincos11 glsincos0 fix extended
uPSI_UMatrix; Gaussian_Elimination fix array[1..30] of Extended
more .ico and .bmp resouces, fix Textmetric type and strtochars() alias StrtoCharSet()
+ Json extension with objects and arrays
+ shortcut Ctrl+Alt+M to jump to output (memo2) console


Sent from sourceforge.net because you indicated interest in https://sourceforge.net/p/maxbox/news/2020/04/maxbox-47282-april-2020/

Also the Wiki has been updated:

--- v223
+++ v224
@@ -113,7 +113,7 @@

 ## Roadmap for maXbox to 2012/13/14/15/16/17/18/19/20 (roadmaX)

-  * Top Version: Win V4.2.4.80 - V3.9.9.195 - Linux V3.8.0 - Mac V1.2.9.3 
+  * Top Version: Win V4.7.4.62  - V3.9.9.195 - Linux V3.8.0 - Mac V1.2.9.3 
   * Screenshots and History 
   * [GUI](http://www.softwareschule.ch/images/maxbox3_screen.png) and [maXbox Form](http://www.softwareschule.ch/download/mediaplayer_mx3.png) and the new [mX3.9 GUI](http://www.softwareschule.ch/images/mx39gui.png)
   * Release available: 
@@ -183,6 +183,7 @@
 * V4.7.1.10 Sep 2019:Tutor 57-70, VState Machine, CGI,MachineLearning +20 Units +Tensorflow dll
 * V4.7.1.20 Nov 2019:Tutor 70-72, EKON 23 Fixing, WebSockets, DRBOBCGI, 5+ overbyte Units
 * V4.7.1.82 Dec 2019:Tutor 70-72, EKON23 Fixing, WebSockets/Spider, PHP_CGI,JS, OpenOffice,7+overbyte Units
+* V4.7.4.64 June 2020: EKON24 Fixing, uPSI_SimpleRSS, Json Base Prometheus, neural CAI, Dendron

  (V5.0.1 2018: MAC Version, FPC, (64-bit), Android and Arduino Dump, Unicode, Classes / Class Diagram) 

A second update:
--- v224 +++ v225 @@ -113,7 +113,7 @@ ## Roadmap for maXbox to 2012/13/14/15/16/17/18/19/20 (roadmaX) - * Top Version: Win V4.7.4.62 - V3.9.9.195 - Linux V3.8.0 - Mac V1.2.9.3 + * Top Version: Win V4.7.4.64 - V3.9.9.195 - Linux V3.8.0 - Mac V1.2.9.3 * Screenshots and History * [GUI](http://www.softwareschule.ch/images/maxbox3_screen.png) and [maXbox Form](http://www.softwareschule.ch/download/mediaplayer_mx3.png) and the new [mX3.9 GUI](http://www.softwareschule.ch/images/mx39gui.png) * Release available: @@ -183,7 +183,7 @@ * V4.7.1.10 Sep 2019:Tutor 57-70, VState Machine, CGI,MachineLearning +20 Units +Tensorflow dll * V4.7.1.20 Nov 2019:Tutor 70-72, EKON 23 Fixing, WebSockets, DRBOBCGI, 5+ overbyte Units * V4.7.1.82 Dec 2019:Tutor 70-72, EKON23 Fixing, WebSockets/Spider, PHP_CGI,JS, OpenOffice,7+overbyte Units -* V4.7.4.62 June 2020: EKON24 Fixing, uPSI_SimpleRSS, Json Base Prometheus, neural CAI +* V4.7.4.64 June 2020: EKON24 Fixing, uPSI_SimpleRSS, Json Base Prometheus, neural CAI, Dendron (V5.0.1 2018: MAC Version, FPC, (64-bit), Android and Arduino Dump, Unicode, Classes / Class Diagram)

Try it online!

Static Methods or not can be a tricky situation.

One rule-of-thumb: ask yourself “Does it make sense to call this method, even if no object has been constructed yet?” If so, it should definitely be static.

So in a class Car you might have a method:

double convertMpgToKpl(double mpg)

…which would be static, because one might want to know what 35mpg converts to, even if nobody has ever built a Car. But this method (which sets the efficiency of one particular Car):

void setMileage(double mpg)

…can’t be static since it’s inconceivable to call the method before any Car has been constructed.

Then I had some spare time and made an online assesment test from linkedlin:

I want to call out briefly this is the newly added official support for the just-released new update to Delphi (and C++Builder) itself: Version 10.4, or “Sydney” and maXbox V 4.7.4.64 scripting engine.

Testing is an integral part of software development life cycle. Various models or approaches are used in the software development process where each model has its own advantages and disadvantages.

Lets compare the real world with a real model and the model itself :


Release Notes maXbox 4.7.4.64 June 2020 mX47


  • 1254 unit uPSI_MaskEdit.pas FCL
  • 1255 unit uPSI_SimpleRSSTypes; BlueHippo
  • 1256 unit uPSI_SimpleRSS; BlueHippo
  • 1257 unit uPSI_psULib.pas Prometheus
  • 1258 unit uPSI_psUFinancial; Prometheus
  • 1259 uPSI_PsAPI_2.pas mX4
  • 1260 uPSI_PersistSettings_2 mX4
  • 1261 uPSI_rfc1213util2.pas IP
  • 1262 uPSI_JTools.pas JCL
  • 1263 unit uPSI_neuralbit.pas CAI
  • 1264 unit uPSI_neuralab.pas CAI
  • 1265 unit uPSI_winsvc2.pas TEK
  • 1266 unit uPSI_wmiserv2.pas TEK
  • 1267 uPSI_neuralcache.pas CAI
  • 1268 uPSI_neuralbyteprediction CAI
  • 1269 unit uPSI_USolarSystem; glscene.org
  • 1270 uPSI_USearchAnagrams.pas DFF
  • 1271 uPSI_JsonsUtilsEx.pas Randolph
  • 1272 unit uPSI_Jsons.pas Randolph
  • 1273 unit uPSI_HashUnit; DFF
  • 1274 uPSI_U_Invertedtext.pas DFF
  • 1275 unit uPSI_Bricks; Dendron
  • 1276 unit uPSI_lifeblocks.pas Dendron

Totals of Function Calls: 32633
SHA1: of 4.7.4.64 DA4C716E31E2A4298013DFFBDA7A98D48650B0C7
CRC32: 3EB27A87: 28.2 MB (29,608,248) bytes

maXbox4 with ICE4
TRIX Model

This was a game contest with the idea aliens on the moon have to be smashed with balls from the earth. Programming time one hour!

SNCF Quadri-Courant CC 40110 Nice

saint indy

Delphi Internet Development with Indy

Delphi Internet Development with Indy

To read

TCP.GetResponse

TCP.SendCmd

TCP.Capture (Indy 10?)

7.6

TIdUDPClient is the base UDP client for sending UDP packets to other destinations. The mostcommonly used method is Send, which uses the Host and Port properties to send a UDP packet. Itaccepts a string as an argument.

There is also a SendBuffer method which performs the same task as Send, except that it accepts aBuffer and Size as arguments.

TIdUDPClient can also be used as a server of sorts to wait and receive incoming UDP packets on anindividual basis.

TIdUDPServer when active creates a listening thread to listen for inbound UDP packets. For each UDP packet received, TIdUDPServer will fire the OnUDPRead event in the main thread, or in the context of the listening thread depending on the value of the ThreadedEvent property.When ThreadedEvent is false, the OnUDPRead event will be fired in the context of the main program thread. When ThreadedEvent is true, the OnUDPRead event is fired in the context of the listener thread.When ThreadedEvent is true or false, its execution will block the receiving of more messages. Because of this the processing of the OnUDPRead event must be quick.

Infos

Introduction to Indy

Connection Closed Gracefully

http://groups.yahoo.com/group/Indy-Dev-Public/

The TTL property is declared as protected in TIdRawBase, and TIdIcmpClient does not promote it to public. You will have to declare a descendant class to gain access to it, ie:

type
TIdIcmpClientAccess = class(TIdIcmpClient);
 
procedure TMainForm.PingFirst;
//…
TIdIcmpClientAccess(IdIcmpClient1).TTL := CurrentTTL;
//…
end;

Indy.Sockets version 10.1.1

Indy Knowlege Base

[Indy10] How to PING?

[Indy10] Comment PINGer?

[Indy10] Comment PINGer?

Introduction

Along with ICS and Synapse, Indy is one of the most use open-source set of Internet components. It supports HTTP, SMTP, ICMP, etc.

Note: All Indy exceptions descend from EIdException. By default, Delphi 7 has at least one item in Tools > Debugger Options > Language Exceptions related to Indy, “Indy EIDSilentException Exceptions”, and, possibly “Indy EIDSocketError Exceptions”… which do not prevent the IDE to fail when running in the by design exception EIdSocketError “Socket Error # 10004”. The reason is that the actual exception is “EIdSocketError”, not “Indy EIDSocketError Exceptions”. Add the former through the Add button, don’t forget to add IdException in the users section, and you won’t be stopped by the IDE anymore.

Upgrading to Indy 10

Delphi 7 ships with Indy 9. Since the only documentation on the Indy website is now based on release 10, and some examples won’t work with older releases, you must remove Indy 9 from the IDE, and install release 10.

There are two possibilities, but both require your uninstalling Indy 9 yourself before installing Indy 10:

Removing Indy9:

  1. Close the Borland Delphi IDE if it is open.
  2. If you are using the version of Indy included in Delphi 6 or 7, use the MSI installer to remove Indy: In “Program Files”, click on the drop-down list before Indy, and select Do Not Install. If you didn’t install Corba, uncheck “Use Visibrocker/CORBA Support” before proceeding with the uninstall
  3. Remove all Indy files from the Delphi directory, including dclIndy*.bpl, Indy*.bpl, the Id*.pas, and the Id*.dcu’s.  Take care that you only remove the old Indy files and not something else.  Be sure that you also remove any Indy*.bpl from your Windows\System32 directory (IndyCore70.bpl, IndyProtocols70.bpl, and IndySystem70.bpl)
  4. When restarting Delphi, it will fail loading the Indy 9 BPL: “Error/Can’t load package c:\program files\borland\delphi\Bin\dclindy70.bpl. The specified module could not be found. Do you want to attempt to load the package the next time a project is loaded?” Just tell it not to try reloading this package the next time.

Manually installing Indy10

  1. Place the new version of Indy in a directory of your choice.  When unzipping, please keep the \source directory for the archive intact because that is used by some build batch files.
  2. In the source directory, there are several batch files.  Run the appropriate one for your version of Indy:
    • FULLD4.BAT – Delphi 4
    • FULLD5.BAT – Delphi 5
    • FULLD6.BAT – Delphi 6
    • FULLD7.BAT – Delphi 7
  3. These batch files create subdirectories in the main Indy directory folder.  They are (D4 for Delphi 4, D5 for Delphi 5, D6 for Delphi 6, and D7 for Delphi 7).  These directories contain:
    • The Indy .DCU’s
    • The Indy Design-Time .BPL
  4. In your Delphi IDE, add the Indy design-time package with Component|Install Package…|Add…  Go to the subdirectory where the Indy .DCU’s and Design-Time .BPL was placed by the batch file.  Add the Design-Time .BPL that is listed.  It usually is named dclIndy followed by the Borland Delphi version and an 0
  5. Add the path where the .DCU’s are located to your environment.  Do this with Tools|Environment Options…|Library…|Library Path…

(Difference with above instructions?) Compiling and installing manually:

Note: All packages are followed by X0 (Where X is your Delphi verison). Example: For Delphi 6, the IndySystem package would be named: IndySystem60.dpk

  1. Download the latest source code
  2. Open and compile .dpk files in the following order:

    Lib\System\IndySystemX0.dpk
    Lib\Core\IndyCoreX0.dpk
    Lib\Protocols\IndyProtocolsX0.dpk

    Lib\SuperCore\IndySuperCoreX0.dpk
    If you are not using SuperCore, then you do not need to compile this package.
     
  3. Now open these .dpk files and click install in the following order:

    Lib\Core\dclIndyCoreX0.dpk
    Lib\Protocols\dcl\IndyProtocolsX0.dpk

    Lib\SuperCore\dcl\SuperCoreX0.dpk
    Only install this if you have compiled SuperCore.

After installing Indy 10, you might get the following error when adding a IdUDPServer widget and code for the UDPRead event: “[Error] Unit1.pas(15): Undeclared identifier: ‘TBytes'”

=> “That is a known Delphi bug, not an Indy one. The bug is that Delphi parses the signature wrong when generating the event handler.  As for why TIdBytes is used in the event, it is because the Intercept system in Indy 10 is based on TIdBytes to begin with.  It Indy 9, it was based on Streams instead.”

Connecting to a server in TCP

Here’s an example from Indy in Depth:

uses […] IdException;
 
[…]
try
    IdTCPClient1.Host := ‘localhost’;
    IdTCPClient1.Port := 80;
 
    try
        try
            IdTCPClient1.Connect;
            // Do your communications here
        finally
            IdTCPClient1.Disconnect;
        end;
    except //Failed during transfer
        on E: EIdException do begin
            ShowMessage(‘A network error occurred during communication: ‘ + E.Message);
        end;
        on E: Exception do begin
            ShowMessage(‘An unknown error occurred during communication: ‘ + E.Message);
        end;
    end;
 
except //Couldn’t even connect
    on E: EIdException do begin
        ShowMessage(‘An network error occurred while trying to connect: ‘ + E.Message);
    end;
    on E: Exception do begin
        ShowMessage(‘An unknown error occurred while trying to connect: ‘ + E.Message);
    end;
end;

Downloading a web page into a variable

The easiest way is to use the open-source IdHTTP component provided with Delphi 6+ and located in the Indy Clients tab. Note that adding this component in a form adds the following units to the project: IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient:

procedure TForm1.Button1Click(Sender: TObject);
begin
    ShowMessage(IdHTTP1.Get(‘http://yahoo.com&#8217;));
end;

Another way is to use UtilMind’s freeware component HTTP GET (‘This component intended for downloading files/documents/results of CGI scripts from the web using standard Microsoft Windows Internet library (winInet.dll) which also used by Internet Explorer.”):

Another way is to use the TDownloadUrl component (but data is saved into a file, not a variable)

uses ExtActns;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
 
    with TDownloadUrl.Create(Self) do
        try
            URL := ‘http://www.acme.com/forum.asp?ID=123‘;
            FileName := ‘forum.html’;
            Execute;
            WebBrowser1.Navigate(ExtractFilePath(Application.ExeName) + ‘forum.html’);
        finally
            Free;
    end;
end;

Here’s how to download a bunch of files that have an increasing suffix:

//From Simple HTML page scraping with Delphi
function Download_HTM(const sURL, sLocalFileName:string): boolean;
begin
  Result:=True;
  with TDownLoadURL.Create(nil) do
  try
    URL:=sURL;
    Filename:=sLocalFileName;
    try
      ExecuteTarget(nil);
    except
      Result:=False
    end;
  finally
    Free;
  end;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
const
  ADPNEWHOTURL=’http://acme/picture_&#8217;;
var
  sPathToF : String;
  iIndex : Integer;
  sPictureFileName : String;
begin
  sPathToPictures := ExtractFilePath(Application.ExeName) + ‘pictures’;
 
  if not DirectoryExists(sPathToPictures) then
    CreateDir(sPathToPictures);
 
  SetCurrentDir(sPathToPictures);
 
  For iIndex := 1 to 274 do begin
    sPictureFileName := ‘picture_’ + Format(‘%.4d’, [iIndex]) + ‘.jpg’;
    Label1.Caption := ‘Source = ‘ + ADPNEWHOTURL + IntToStr(iIndex) + ‘ Target = ‘ + sPictureFileName;
    if NOT Download_HTM(ADPNEWHOTURL + IntToStr(iIndex),sPictureFileName) then begin
      ShowMessage(‘Error in HTML file download ‘ + IntToStr(iIndex));
      Exit;
    end;
    Application.ProcessMessages;
  end;
 
end;

Downloading a web page using the POST method

uses IdMultipartFormData;
[…]
data := TIdMultiPartFormDataStream.Create;
try
    //Note: If the variable uses accented characters like é, type them as is,and
    //IdMultipartFormData will take care of the conversion to eg. %E9
    data.AddFormField(‘search’, ‘1’);
    //bad
    Memo1.Lines.Text := IdHTTP1.Post(‘http://www.acme.com/index.html&#8217;, data);
except
    //Note: Not called in IDE, but OK otherwise
    ShowMessage(intToStr(IdHTTP1.Response.ResponseCode));
end;
data.Free;

Pinging a server

Here’s how to do it using Indy 9 (The version that ships with Delphi 7):

procedure TForm1.Timer1Timer(Sender: TObject);
var
  Icon: TIcon;
  Index : Integer;
 
begin
  IdIcmpClient1.Host := ‘(some unreachable server here)’;
  IdIcmpClient1.ReceiveTimeout := 2000; //2 seconds
  //Try/except to get rid of the Socket Error #10004 Interrupted System Call
  try
    IdIcmpClient1.Ping;
  except
    ShowMessage(‘Error when pinging’);
  end;
end;
 
procedure TForm1.IdIcmpClient1Reply(ASender: TComponent; const AReplyStatus: TReplyStatus);
begin
  if (AReplyStatus.ReplyStatusType = rsTimeOut) or (AReplyStatus.ReplyStatusType = rsErrorUnreachable) then begin
    Label1.Caption := ‘Computer is down.’;
  end else begin
    Label1.Caption := ‘Packet round trip time: ‘ + IntToStr(AReplyStatus.MsRoundTripTime) + ‘ ms.’;
  end;
end;

Another example:

uses
  Windows, […] IdException;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  IdIcmpClient1.Host:= ‘www.cisco.com’;
  try
    IdIcmpClient1.Ping();
  except
    case IdIcmpClient1.ReplyStatus.ReplyStatusType of
      rsEcho:
        begin
          ListBox1.Items.Append(format(‘response from host %s in %d millisec.’,
          [IdIcmpClient1.ReplyStatus.FromIpAddress,
          IdIcmpClient1.ReplyStatus.MsRoundTripTime]));
        end;
      rsError:
        ListBox1.Items.Append(‘Unknown error.’);
      rsTimeOut:
        ListBox1.Items.Append(‘Timed out.’);
      rsErrorUnreachable:
        ListBox1.Items.Append(format(‘Host %s reports destination network unreachable.’,
        [IdIcmpClient1.ReplyStatus.FromIpAddress]));
      rsErrorTTLExceeded:
        ListBox1.Items.Append(format(‘Hope %d %s: TTL expired.’,
        [IdIcmpClient1.TTL, IdIcmpClient1.ReplyStatus.FromIpAddress]));
    end; // case
 
    on E: EIdException do begin
      ListBox1.Items.Append(‘Error : ‘ + E.Message);
    end;
  end; //Except
end;

Q&A

Indy vs. ICS vs. Synape

Those three open-source projects offer support for IP connections.

  • Indy : blocking sockets make for easier programming; ships with Delphi; some incompatibilities between Indy 9 and 10 require rewriting code
  • ICS :
  • Synapse : doesn’t install in the IDE, ie. no widgets in forms, just units

How to prevent the UI from freezing while waiting on a socket to respond?

“Indy has a special component that solves the User Interface freeze problem transparently. Simply add one TIdAntiFreeze anywhere in your application, and you can perform standard blocking Indy calls in your program without the User Interface being frozen.

Since the user interface freeze is only affected by blocking calls in the main thread, TIdAntiFreeze only affects Indy calls made from the main thread. If an application uses Indy in threads, TIdAntiFreeze is not required. If used, it will only affect calls made from the main thread.”

Socket Error # 10004 Interrupted system call when using Indy components?

In Tools > Debugger Options > Language Exceptions, add EIdSocketError to the list of exceptions to ignore, and use a try/except to go around the exception.

Resources

(function() { var cx = ‘018380135220369063761:xtaiscqnih4’; var gcse = document.createElement(‘script’); gcse.type = ‘text/javascript’; gcse.async = true; gcse.src = (document.location.protocol == ‘https:’ ? ‘https:’ : ‘http:’) + ‘//www.google.com/cse/cse.js?cx=’ + cx; var s = document.getElementsByTagName(‘script’)[0]; s.parentNode.insertBefore(gcse, s); })();

Train Time

saint source

Programming in Delphi

Programming in Delphi

Introduction

The Delphi language was formerly known as Object Pascal, and is an object-oriented version of the venerable Pascal language, combined by Borland with a Visual Basic-like RAD tool that lets you write fast GUI applications with no run-time, a very rich set of components (VCLs) that can be statically compiled into the EXE, and an encapsulation of most of the Windows API for easier access to the underlying OS. If this reminds you of .Net, it’s no chance since both Delphi and the .Net framework were designed by the same person, Anders Hejlsberg. For more infos, read Delphi history � from Pascal to Diamondback (Delphi 2005) by Zarko Gajic.

As of April 2005, Delphi is available as Delphi 2005, a.k.a. Delphi 9, to write Win32 or .Net applications, but you might be able to still get your hands on Delphi 7 (to write Win32, and Linux applications by using Kylix and the Qt widgets-based CLX component library instead of the Windows-only VCL widgets), or Delphi 8 (to get you started writing .Net applications; D7 has a command-line version of the Delphi CLI compiler, but it was really meant as a learning tool.) Note that D8 comes with Delphi 7.1. Delphi 2005 supports the 1.1 .Net framework.

Setup

If you just want to get started and learn Delphi, the $99 Personal edition of Delphi 7 is all you need is love. If you prefer to start developing for .Net, try Delphi 9, a.k.a. Delphi 2005. In October 2006, Borland relaunched its Turbo brand, and offers two versions: Explorer, which are free but doesn’t allow installing third-party components, and Professional, which aren’t. Turbo Delphi Win32 is Delphi 2006 (a.k.a. Borland Developer Studio) with just the Delphi for Windows32 personality.

FWIW, the main extras offered by the Enterprise version of Delphi 7 are IntraWeb from AToZed (Framework + component set for building web apps in a RAD manner), Rave Visual Designer (Visual reporting tool), BizSnap (to create web services,) and Model Maker (UML stuff.)

IDE

  1. Create shortcut on desktop, with Start In = where you save your projects
  2. Install the latest Update and hot-fixes
  3. Get rid of news: Tools > Env’t Options > Delphi Direct: Uncheck “Automatically poll network”.
  4. Combine Object TreeView, Object Inspector, Project Manager
  5. Remove useless toolbars
  6. Hide line numbers and gutter
  7. Save desktop
  8. Install CnWizards
  9. Install GExperts
  10. Install memory-related add-on’s: FastMM, madExcept (“replaces Delphi’s exception handling with a much more intelligent solution”), MemProof (“FREE heap memory and resource ‘leak’ debugger for Borland’s 32-bit family of compilers”)
  11. Install third-party components
  12. DOESN’T WORK (D2007) Disable Welcome Page (HKEY_CURRENT_USER\Software\Borland\BDS\5.0\Known IDE Packages\Delphi\$(BDS)\Bin\startpageide100.bpl)
  13. (D2007) Install DDevExtensions to get TAB/Shift-TAB indenting
  14. (D2007) Remove Welcome Page (set HKEY_CURRENT_USER\Software\Borland\BDS\<version #>\Known IDE Packages\Delphi\$(BDS)\Bin\startpageide100.bpl to empty string)
  15. (D2007) Set the default directory to save new projects by editing HKEY_CURRENT_USER\Software\Borland\BDS\5.0\Globals\DefaultProjectsDirectory

How to add bookmarks?

To add bookmarks to source code so you can jump to locations, press CTRL-SHIFT, and any number between 0 and 9.

To jump to that location, hit CTRL and the number of the bookmark (doesn’t work in D7 with default settings). Or you can use CnWizards, and hit CTRL-SHIFT-B to get a list of bookmarks.

Can I indent a block of code in one go?

If you’d rather use the familiar TAB button to indent a whole block, install Two Desk’s Castalia add-in to the IDE, or the free CnWizards (a.k.a. CnPack IDE Wizards).

Can I comment a whole block in one go?

If you are running Delphi Pro and above, check out GExperts or CnWizards. If you are using the Personal or Standard edition, looks like the only way is to use the { and } syntax, with no menu or keyboard shortcut available.

Recommended components and packages

Some are open-source, some are just freeware, and yet others are commercial:

Sites to check for Delphi components

Must-have third-party tools

  • Delphi2007+ lets you add “ReportMemoryLeaksOnShutdown := True;” to a project’s DPR file. There are alternatives: Memory Sleuth NuMega, etc.

Delphi in a nutshell

Components and packages

Note: In the Delphi literature, depending on the context, “package” refers to either a DPK master file and PAS/DCU source files, or the resulting, compiled BPL file which contains all the DCU files.

Components can be distributed either as

  • a bunch of (more or less) independent source files (*.PAS) that you will add to your project and that will be statically compiled into the EXE,
  • a bunch of compiled unit files (*.DCU) that you add to your project via the Uses section and will be compiled statically into the EXE,
  • a bunch of source files (referenced by a .DPK master list file, ) to be compiled into a single package file (.BPL),
  • a bunch of compiled files (.DCU) and a BPK master file that you can use to build a design-time component and add it to the IDE, or as
  • a package file (.BPL) already compiled for you.

Typically, commercial components are provided as binary files, but some can also be bought with source files.

Individual components (ie. PAS or DCU files) can be added to an existing package, or to a brand new package through either File > Open (select a DPK file, click on Add, and compile) or Component > Install Component (when adding to an existing package, the default file is DCLUSR.DPK).

A package file has the extension BPL, and is just a Borland-specific version of a DLL with added functions like GetPackageInfoTable(), ie. routines that live in a file separate from the caller EXE, and that can be loaded dynamically when needed. Use the Bin\TDUMP.EXE command-line Borland utility to display information containted in a BPL file.

Once installed, packages are listed in the Registry under HKEY_CURRENT_USER\Software\Borland\Delphi\<version>\Known Packages . For Delphi to find components, they must be located in known directories through the Tools > Environment Options > Library.

Packages come in three different forms:

  • Those that are design-time-only (ie. meant to be installed in the IDE),
  • Those that are run-time-only (used only when running the EXE; must be rare, since developers want the choice of static or dynamic linking), and
  • Those that do both.

Components meant to be used in the IDE can only be installed as a package, ie. a DPK master file along with one or more PAS files to be compiled into DCUs and aggregated in a single BPL file that will be registered into the IDE.

Note that design-time packages and run-time packages are two different beasts: The former adds itself to a palette in the IDE and provides an interface to access its properties, routines, and events; The latter is used by applications that were compiled with run-time packages, ie. dynamic linking. Some BPLs are both design-time and run-time, so I guess they have a switch somewhere in the code that lets me act differently depending on the context.

From what I understand, a typical situation is thus:

  • if the component offers a design-time interface, this requires installing a BPL in the IDE
  • compiling this component statically requires compiling some DCUs into the EXE; compiling this component for dynamic loading means reading headers and symbol information from a DCP file, and providing the run-time BPL (which, in the end, is just an aggregation of all the DCUs that make up this component.)

Depending on the “Build with runtime packages” checkbox in Project > Options > Packages, the compiler will either (if disabled) include all the DCU files into the EXE, or (if enabled) use an external BPL file, that you’ll have to distribute in addition to the EXE. In other words, this is where you decide whether to link third-party components statically into the EXE, or dynamically by loading BPLs at run-time.

If the packages don’t change often, it might be a good idea to use dynamic linking, so that you only need to distribute the EXE for updates. On the other hand, dynamic run-time packages contain all the routines, even those that your EXE doesn’t use, while, when using statically-linked packages, the IDE will only include stuff that your EXE actually use. In the end, a statically-linked EXE can turn out to be smaller that a bare EXE and external BPLs.

Finally, if resource files are used (RES or DCR), Delphi will need those to compile a package successfully. Bitmaps for the components that will appear in the palette are saved in the DCR files.

The source files, either source (.PAS) or compiled (.DCU) aren’t needed to use a component; They are only needed if you want to compile the component yourself.

Important: As DCUs are version-dependent, a package can only be installed in the same version of the IDE that was used to compile it. That’s the reason why some components are distributed as source code that you must compile yourself into a package before adding it to the IDE. The alternative for commercial components is to generate multiple versions of the package, one for each version of the IDE that they wish to support.

Moving a design package to another host requires copying the following files: BPL, DCP, possibly DCR resources files, hitting the Component > Install Packages menu, and clicking on Add.

In addition to individual packages, it is possible to create a package collection (DPC) to make it easier to distribute the different files that make up a package. A DPC will contain DCP, DCU, and BPL files. This type of file requires a Package Collection Editor (PCE), which is a source file used to define a DPC file. A DPC file is created through Tools > Package Collection Editor.

More information:

Questions

  • If the independent DCUs and the ones aggregated in a run-time BPL are identical, why don’t commercial components just come as a bunch of DCUs that developers who want to use dynamic linking will compile themselves into a BPL?
  • When using a design-time package, I am provided with a BPL that will be added to the palette. In addition, DCU files are required to allow for static linking. On the other hand, when using a run-time package, the package designer must provide a DCP since it is required to let the compiler know how to link to the BPL file for dynamic loading. Correct?
  • When creating a package that is both a design- and run-time package, are there two different BPL files, or is there some kind of switch in the file that lets the compiler use the same file in two different contexts? From reading DsgnIntf.dcu not found, it seems that for a while, Borland didn’t force component developers to write two versions, one for the IDE and one as a run-time package. Or are design-time BPLs and run-time BPLs two totally different beasts?
  • How can I tell if a BPL is design-time or run-time? Because the IDE will complain if I try to a run-time package to the list of design-time packages?

Making sense of extensions

Extension

Acronym

Role

PAS

Pascal

Source code; Like .C in C

DCU

Delphi Compiled Unit

Compiled version of .PAS files; Similar to .OBJ file in C

DFM

Delphi Form

Describes a form, and what it contains

DPR

Delphi Project

EXE project master file

RC

Resource

Clear-text resource file

RES

Resource

Binary resource file from RC

DRC

Delphi Resource

Compiler-generated resources. Usually strings; it’s pretty much a .RC file without a correspondent .RES

DCR

Delphi Component Resource

Resource files; Includes bitmaps used for components added to the IDE

INC

Include?

Source code; Like .INC in C

 

 

 

DCP

Delphi Compiled Package

Used for EXEs built with run-time BPLs to let the compiler know how to link to the BPL at run-time; Doesn’t include compiled code, which is stored in DCU or BPL files

BPL

Borland Package Library

Delphi-specific DLL, ie library loaded at run-time

DPK

Delphi Package ???

Project master file when developing a package; equivalent to .DPR for EXE projects

DPC

Delphi Package Collection

?

DPKW

 

Like DPK

 

 

 

BPG

Borland Project Group

Used to keep track of projects when opening more than one project in the IDE

BPK

?

?

BPI

?

?

 

 

 

CFG

Compiler Configuration

Compiler settings; Similar to DOF

DOF

Delphi Options File?

Project options

DSK

Desktop

Desktop settings

 

 

 

 

 

 

 

 

 

 

 

 

Menus of interest

  • New and Open: To create blank files or projects, start from templates (regular windows, dialogs, MDI/SDI, etc.), or open existing files and projects, including packages (to install components)
  • View: Project Manager (to list all the units that make up a project), Object Inspector (to view parameters of a unit), Object Tree View (To list widgets contained in a form), Desktops (to save, and apply a desktop definition, so that windows are displayed in a way you like), Toggle Form Unit (also accessible through F12)
  • Project : to manage files and projects, import a type library for COM objects, add stuff to the source control, compile and/or run a project
  • Components: To create or install components (.PAS files), and install packages. Install Component: Into existing package (Unit file name .PAS or .DCU + Package file name = dclusr.dpk) or Into new package

Getting started

Skeleton of a source file

A typical Delphi GUI program is a set of units (*.PAS) which contain source code, and are listed in a project (.DPR file), while the forms (windows) are described in files with the DFM extension, ie. DPR = PAS + DFM.

Here’s a skeleton of a unit:

//Name of the unit, which can then be referenced in other source files (a unit name must be unique within a project)
unit Unit1;
 
//List of public stuff, eg. variables that can be accessed from other source files
interface
 
uses  { List of units goes here }
 
  { Interface section goes here }
 
//Actual code of this source file
implementation
 
uses  { List of units goes here }
 
  { Implementation section goes here }
 
initialization
  { Initialization section goes here }
 
finalization
  { Finalization section goes here }
 
//A source file must end with “end.”
end.

Hello, world! (console)

Open your favorite editor, save the file as console.pas, and copy/paste the following code:

program Console;
 
{$APPTYPE CONSOLE}
 
var MyMessage: string;
 
begin
  MyMessage := ‘Hello world!’;
  Writeln(MyMessage);
end.

Open a DOS box, compile the program with “dcc32.exe console”, and run the compiled as with “console.exe”.

Hello, World! (GUI)

In the empty form that shows up when starting Delphi, add a label and a pushbutton, double-click on the button, and add the following code to the Button1Click() routine:

Label1.Caption := ‘Hello, world!’;

Hit F9 to run the application, and click on the pushbutton to see the text of the label change.

Showing a message box with a  default button

With D7 at least, Delphi’s MessageDlg doesn’t let you select a default button, which is unfortunate for critical choices. You’ll have to use Win32’s MessageBox() instead:

if MessageBox(Handle,’text’,’caption’,MB_OKCANCEL or MB_ICONQUESTION or MB_DEFBUTTON2 ) = IDCANCEL then begin
    exit;
end else begin
    ShowMessage(‘ok’);
end;

Dynamic objects

When you add a control on a form at design-time, Delphi takes care of creating and freeing the object, but those tasks are your responsibility when creating objects dynamically, at run-time.

The important point is freeing the object from memory, or your application will leak memory.

There are three ways to handle this:

Declare a variable, call the class’ Create() method, and end with Free(), preferably in a try/finally structure:

var
    MyObj : TObj;
begin
    with TObj.Create(nil) do
        try
            //Do stuff
        finally
           Free;
    end;

A second way is to use the With structure, and set the instance’s owner as a form, so that, even if you forgot to call Free, Delphi will free the object from memory when it kills the parent form (Actually, you should NOT call Free, and let the owner free the instance from memory):

var
    MyObj : TObj;
begin
    with TObj.Create(Self) do begin
        //Do stuff
    end;

Note that the time to dynamically create components with owners is much slower than that to create components without owners.

A third way is to use the With structure with Nil as the parent, but in this case, Free() must be called explicitely:

with TObj.Create(nil) do
    try
        //Do stuff
    finally
       Free;
    end;
end;

Checking for memory leaks

Since D2006, Delphi includes a way to check for memory leaks in the IDE once the application has terminated. To enable this, just add the following line in the Project’s DPR file (via Project > View Source):

begin
  ReportMemoryLeaksOnShutdown :=true;
  Application.Initialize;

Here’s an example to trigger an error:

procedure TForm1.Button1Click(Sender: TObject);
var
  MySL : TStringList;
begin
  MySL := TStringList.Create;
end;

Reading from a text file

Here, we’ll read the file line by line:

procedure TForm1.Button1Click(Sender: TObject);
var
  myFile : TextFile;
  text   : string;
  bit : string;
begin
  AssignFile(myFile, ‘C:\test.txt’);
  try
    Reset(myFile);
    while not Eof(myFile) do
    begin
      ReadLN(myFile,bit);
      text := text + bit + #13#10;
    end;
  finally
    ShowMessage(text);
    CloseFile(myFile);
  end;
 
end;

A faster way:

function LoadFile(const FileName: TFileName): string;
begin
  with TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite) do begin
    try
      SetLength(Result, Size);
      Read(Pointer(Result)^, Size);
    except
      Result := ”;  // Deallocates memory
      Free;
      raise;
    end;
    Free;
  end;
end;
 
FileContents := LoadFile(‘rss.xml’);

ExtractFileDir() in a DataModule?

Application is declared in the forms unit.  As an alternative you can change “Application.ExeName” to “ParamStr(0)”.

Reading from a tab-delimited file

Here’s how to read each line of a tab-delimited text file, and save this into an SQLite database:

With ASQLite3DB1 do begin
    DefaultDir := ExtractFileDir(Application.ExeName);
    Database := ‘test.sqlite’;
    CharacterEncoding := ‘STANDARD’;
    Open;
    SQLite3_ExecSQL(‘CREATE TABLE IF NOT EXISTS mytable (id INTEGER PRIMARY KEY, label VARCHAR)’);
end;
 
AssignFile(SomeTxtFile, FILE2PARSE) ;
Reset(SomeTxtFile) ;
ASQLite3DB1.SQLite3_ExecSQL(‘BEGIN;’);
 
while not EOF(SomeTxtFile) do begin
    ReadLn(SomeTxtFile, buffer) ;
 
    PerlRegEx1.RegEx := ‘^([^d].+)\s(\d+)$’;
    PerlRegEx1.Options := [preCaseLess];
    PerlRegEx1.Subject := buffer;
    If PerlRegEx1.Match then begin
        row := Format(‘INSERT INTO mytable (id,label) VALUES (%s,”%s”);’,[PerlRegEx1.SubExpressions[2],PerlRegEx1.SubExpressions[1]]);
        ASQLite3DB1.SQLite3_ExecSQL(row);
    end;
end;
 
ASQLite3DB1.SQLite3_ExecSQL(‘COMMIT;’);
ASQLite3DB1.Close;
CloseFile(SomeTxtFile);

Writing into a text file

var
  myFile : TextFile;
  letter : char;
  text   : string;
 
begin
  AssignFile(myFile, ‘Test.txt’);
  ReWrite(myFile);
 
  WriteLn(myFile, ‘Hello, world!’);
 
  CloseFile(myFile);
end;

Alternatively:

procedure SaveFile(const FileName: TFileName; const content: string);
begin
  with TFileStream.Create(FileName, fmCreate) do
    try
      Write(Pointer(content)^, Length(content));
    finally
      Free;
    end;
end;

Rewinding a text file

Here’s how to set the cursor back to the beginning of a text file, ie. not a binary file that uses records:

var
    dummy : TextFile;
 
begin
    AssignFile(dummy, ‘dummy.txt’);
 
    ReWrite(dummy);
    WriteLn(dummy, ‘123’);
 
    ReWrite(dummy);
    WriteLn(dummy, ‘345’);
 
    CloseFile(dummy);

Here’s another way :

var
    test : TFileStream;
    status : String;
 
begin
    status := ‘test’;
 
    test := TFileStream.Create(‘test.txt’,fmCreate);
    test.Write(Pointer(status)^,Length(status));
    test.Seek(0, soFromBeginning);
    test.Free;

Playing with radio buttons

At design-time, the best way to add radio buttons to a form is by first adding a radiogroup object, and modify its Items property to add radio buttons.

Here’s how to display the radio button currently selected, if any:

  ShowMessage(Radiogroup1.Items.Strings[RadioGroup1.ItemIndex]);

A more complicated way:

  for Index := 0 to RadioGroup1.Items.Count – 1 do begin
    if RadioGroup1.ItemIndex = Index then begin
      ShowMessage(RadioGroup1.Items[Index]);
    end;
  end;

Here’s how to clear it:

RadioGroup1.ItemIndex:=-1;

Playing with TStringList hashed arrays

In addition to indexes, a TStringList array can use names so as to build name=value items. Here are some examples:

var
    indexclassifications : TStringList;
    i : Integer;
 
begin
    indexclassifications := TStringList.Create;
 
    indexclassifications.Add(‘unix=good’);
    indexclassifications[0] := ‘windows=bad’;
 
    for i := 0 to indexclassifications.Count-1 do begin
        ShowMessage(indexclassifications[i]);
        ShowMessage(indexclassifications.Names[i]);
 
        ShowMessage(indexclassifications.ValueFromIndex[i]);
        ShowMessage(indexclassifications.Values[indexclassifications.Names[i]]);
    end;
 
    indexclassifications.Free;

An alternative is Ciaran McCreesh’s Hash Library.

Playing with a ListBox

Adding items

ListBox1.Items.Add(‘Hello’);

Adding an item at a specific location in the list

ListBox1.Items.Insert(3,’Hello’);

Reading the item that was double-clicked

procedure TForm1.ListBox1DblClick(Sender: TObject);
var
  listBox : TListBox;
  index   : Integer;
begin
  listBox := TListBox(Sender);
  index   := listBox.ItemIndex;
  ShowMessage(listBox.Items[index]);
end;

Selecting a directory

Here’s how to display a dialog box so the user can choose a directory:

procedure TForm1.Button1Click(Sender: TObject);
var
  chosenDirectory : string;
  options : TSelectDirOpts;
 
begin
  chosenDirectory := ‘C:\’;
  if SelectDirectory(chosenDirectory, options, 0) then
    LabeledEdit1.Text :=chosenDirectory + ‘\’;
 
end;

Closing an application

Two possibilites, using either Sys.Close() or Application.Terminate(), but the latter doesn’t trigger the onClose or onCloseQuer events:

//If app already ran, make the button Close the app
If (Button1.Caption = ‘Close’) then begin
    Close;
    Exit;
end;

Downloading a web page into a variable

Moved to Internet Development with Indy components

Removing unwanted characters

Here’s how to strip unwanted characters from a string:

function CleanInput(input : String) : String;
var
  output : string;
  index : Integer;
begin
  output := StringReplace(input, #9, ”,[rfReplaceAll, rfIgnoreCase]);
  output := StringReplace(output, #10, ”,[rfReplaceAll, rfIgnoreCase]);
  output := StringReplace(output, #13, ”,[rfReplaceAll, rfIgnoreCase]);
  output := StringReplace(output, ‘  ‘, ”,[rfReplaceAll, rfIgnoreCase]);
  output := StringReplace(output, ‘&nbsp;’, ”,[rfReplaceAll, rfIgnoreCase]);
  output := StringReplace(output, ‘&nbsp’, ”,[rfReplaceAll, rfIgnoreCase]);
  output := StringReplace(output, ‘<br>’, ”,[rfReplaceAll, rfIgnoreCase]);
  Result := output;
end;

PINGing a server

Here’s how to do it using the open-source ICS tools:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Ping1.Address := ‘127.0.0.1’;
  Ping1.Ping;
end;
 
procedure TForm1.Ping1EchoReply(Sender, Icmp: TObject; Status: Integer);
begin
  if Status <> 0 then
      { Success }
      Label1.Caption := ‘Server ‘ + Ping1.HostIP + ‘ alive @ ‘ + TimeToStr(Time)
  else
      { Failure }
      Label1.Caption := ‘Server ‘ + Ping1.HostIP + ‘ dead @ ‘ + TimeToStr(Time) +
        #13#10 + Ping1.ErrorString + ‘. Status = ‘ + IntToStr(Ping1.Reply.Status);
end;  

Here’s how to do it using Indy 9 (? The one that ships with Delphi 7):

Moved to Internet Development with Indy components

Checking the class of an object

If you need to display the class of an object:

ShowMessage(MyObj.ClassName);

Casting an object

Sometimes, it’s necessary to help Delphi by casting an object:

//Otherwise, E2010 Incompatible types: ‘TMemoryStream’ and ‘TStream’
PerlRegEx1.Subject := StreamToText(TMemoryStream(RcvdStream));

Playing with date and time

Here’s how to time tasks:

var
  StartTime,StopTime : TDateTime;
begin
  StartTime := Now;
  ListBox1.Items.Add (TimeToStr (StartTime));
 
  […]
 
  StopTime := Now;
  ListBox1.Items.Add(‘After doing stuff ‘ + FormatDateTime (‘hh:nn:ss’, StopTime – StartTime));

More information:

Reading caller ID information through a modem

Using the Treeview control

TreeView1.LoadFromFile(‘myTABBEDfile.txt’);

Using the Listview control

(stolen from D7’s help file)

procedure TForm1.PopulatClick(Sender: TObject);
const
  Names: array[0..5, 0..1] of string = (
    (‘Rubble’, ‘Barney’),
    (‘Michael’, ‘Johnson’),
    (‘Bunny’, ‘Bugs’),
    (‘Silver’, ‘HiHo’),
    (‘Simpson’, ‘Bart’),
    (‘Squirrel’, ‘Rocky’)
    );
 
var
  NewItem : TListItem;
  ListItem : TListItem;
  ListView: TListView;
  NewColumn: TListColumn;
  I: Integer;
 
begin
  with ListView1 do
  begin
    ViewStyle := vsReport;
    RowSelect := True;
 
    NewColumn := Columns.Add;
    NewColumn.Caption := ‘Last’;
    NewColumn := Columns.Add;
    NewColumn.Caption := ‘First’;
 
    for I := Low(Names) to High(Names) do begin
      ListItem := Items.Add;
      ListItem.Caption := Names[I][0];
      ListItem.SubItems.Add(Names[I][1]);
    end;
  end;
 
end;

Arrays

Delphi supports static and dynamic arrays. To make things a bit confusing, it uses the same syntax “array of” to declare dynamic arrays, and so-called “open arrays”, ie. arrays (either static or dynamic) passed as parameters to a routine.

Dynamic arrays are really a one-dimensional array that holds pointers to other arrays, and each cell can point to arrays of different dimensions:

SetLength(MyArray[3],15); //Array[3] points to a fifteen-column array
SetLength(MyArray[2],5); //Array[2] points to a five-column array

As a result, Delphi cannot provide VisualBasic’s UBound(MyArray,x) where x is either 1, 2, or 3, and High(MyArray) returns the upper bound of the array. If one of the cells in the array uses a different dimension from the other cells, you’ll have to call High(MyArray[thiscell]) to get is upper bound.

Here’s an example:

type
    TDigits = array of array of Integer;
 
procedure MyFunc(A: TDigits);
begin
    //4
    ShowMessage(IntToStr(High(A)));
    //9
    ShowMessage(IntToStr(High(A[0])));
    //6
    ShowMessage(IntToStr(High(A[2])));
end;
 
[…]
 
var
    MyArray : TDigits;
begin
    SetLength(MyArray,5,10); //5 rows, 10 columns each
    SetLength(MyArray[2],7); //We can use a different dimension for one cell
 
    MyFunc(MyArray);
end;

“Arrays can be allocated statically or dynamically.

Static arrays:

var MyArray: array[1..100] of Char;

Dynamic arrays:

var MyFlexibleArray: array of Real;
SetLength(MyFlexibleArray, 20);

To deallocate a dynamic array, assign nil to a variable that references the array or pass the variable to Finalize; either of these methods disposes of the array, provided there are no other references to it. Dynamic arrays are automatically released when their reference-count drops to zero.”

“If X and Y are variables of the same dynamic-array type, X := Y points X to the same array as Y.

Unlike strings and static arrays, COPY-ON-WRITE is not employed for dynamic arrays, so they are not automatically copied before they are written to. In contrast, to make an independent copy of a dynamic array, you must use the global Copy function.”

“In some (???) function and procedure declarations, array parameters are represented as array of baseType, without any index types specified. For example,

function CheckStrings(A: array of string): Boolean;

This indicates that the function operates on all arrays of the specified base type, regardless of their size, how they are indexed, or whether they are allocated statically or dynamically. See Open array parameters.”

If you need to pass an array to a routine, you cannot set its size directly, ie.

procedure Sort(A: array[1..10] of Integer); //error

won’t work. Instead, you must either create a type…

type TDigits = array[1..10] of Integer;
procedure Sort(A: TDigits);

…or use open arrays. Open array parameters allow arrays of different sizes to be passed to the same procedure or function:

procedure Add(A: array of Integer);
 
;Note: open arrays are always zero-based., regardless of which Low() you chose to declare the array.
;ie. array[1..4] of Integer won’t work as intended
 
procedure MyCallingFunction;
    var Temp: array[0..3] of Integer;
 
    Temp[0] := 5;
    Temp[1] := 7;
    Temp[2] := I;
    Temp[3] := I + J;
 
    Add(Temp);
end;

To read:

  • Open array parameters and array of const (“Usually, you can pass open arrays as const parameters. Open array parameters that are not passed as const will entirely be copied into local storage of the routine. The array is simply passed by reference, but if it is not declared const, the hidden start code of the routine will allocate room on the stack and copy the entire array to that local storage, using the reference as source address. For large arrays, this can be very inefficient. So if you don’t need to modify items in the array locally, make the open array parameter const.”)
  • Delphi Basics – Arrays
  • Understanding and Using Array data types in Delphi

Associative array (“hash”)

You can use Delphi’s TStringList object:

var
  myhash : TStringList;
  Index : Integer;
 
begin
  myhash := TStringList.Create;
  myhash.Add(‘mykey=myvalue’);
  myhash.Add(‘mykey2=myvalue2’);
 
  ShowMessage(myhash.Values[‘mykey’]);
 
  for Index := 0 to myhash.Count-1 do begin
    ListBox1.Items.Add(myhash.Names[Index] + ‘=’ + myhash.ValueFromIndex[Index]);
  end;
  myhash.Free;
end;

Alternative:

https://svn.openxp.de/openxp/trunk/xplib/hashes.pas

Here’s unit with those TIntegerHash and TStringHash, described @ http://www.undu.com/Articles/020604.html

Usage of it is really simple! Just add ‘hashes’ (filename of .pas file) to uses clause and then somewhere in code write:

var
  hash : TStringHash;
begin
  hash := TStringHash.Create;
  try
    hash[‘one’] := ‘viens’;
    hash[‘two’] := ‘divi’;
    ShowMessage(hash[‘one’]);
    ShowMessage(hash[‘two’]);
  finally
    hash.Free;
  end;

Delphi and databases

The big picture

BDE

BDE + SQL Links or ODBC

DB-agnostic solutions: dbExpress (read-only -> ClientDataSet/Provider), dbGo/ADOExpress

DB-specific connectors (ZeosLib, Interbase Express/IBX or Interbase Objects/IBO, etc.)

Note: IBX’s IBTable, IBQuery/IBUpdateSQL, and IBStoredProc are intended for compatibility with older BDE components. For new applications, you should generally use the IBDataSet component, which allows you to work with a live result set obtained by executing a select query. It basically merges IBQuery with IBUpdateSQL in a single component.

Using an IBQuery that hosts the SQL select statement together with an IBUpdateSQL component that hosts the insert, update, and delete SQL statements is a typical approach from BDE applications.

ClientDataSet/MyBase (requires the entire table to be loaded in memory to access even a single record)

Multi-tier with DataSnap (formerly known as Middle-tier Distributed Application Services, or MIDAS)

BlackFish SQL

DB, query/table datasets, datasource, DBGrid, UpdateSQL

Transactions

 

Query/Table: Dynamic (created by component) vs. persistent (createad a designtime through Fields editor) fields

Query: Params vs. FieldsByName/Fields?

Query/UpdateSQL: Why both?

SELECT+Open, INSERT/UPDATE/DELETE + ExecSQL

 

Regular SQL vs. parametric queries: When you need slightly different versions of the same SQL query, instead of modifying the text of the query itself each time, you can write a query with a parameter and change the value of the parameter, eg. “select * from employee where job_country = :country”.

Notice that all the data-aware components are unrelated to the data-access technology, provided the data-access component inherits from TDataSet.

DBLookupListBox or DBLookupComboBox. The DBLookupComboBox component can be connected to two data sources at the same time: one source containing the data and a second containing the display data.

Datasets: You can modify data in the active buffer only after you explicitly declare you want to do so, by giving the Edit command to the dataset. You can also use the Insert command to create a new blank record and close both operations (insert or edit) by giving a Post command.

To access data from the active record, use the dataset’ Field components, which are by default automatically created when a dataset component is created. These field components are stored in the dataset’s Fields array property. You can access these values by number (accessing the array directly) or by name (using the FieldByName method). Each field can be used to read or modify the current record’s data by using its Value property or type-specific properties such as AsDate, AsString, AsInteger, and so on.

Note: When you set field properties related to data input or output, the changes apply to every record in the table. When you set properties related to the value of the field, however, you always refer to the current record only.

Creating the field components each time a dataset is opened is only a default behavior. As an alternative, you can create the field components at design time, using the Fields Editor.

The VCL includes a number of field class types. Delphi automatically uses one of them depending on the data definition in the database, when you open a table at run time or when you use the Fields Editor at design time.

Types of fields: Data, Calculated (OnCalcFields event), Lookup

Add field (from database) vs. New field (created manually in dataset): Note that fields that are created at design-time with the Fields Editor are the only ones that will be available at run time (Fields, FieldByName). When a program opens a table at run time, if there are no design-time field components, Delphi creates field objects corresponding to the table definition. If there are some design-time fields, however, Delphi uses those fields without adding any extra field objects.

A TField component has both a Name property and a FieldName property. The Name property is the usual component name. The FieldName property is either the name of the column in the database table or the name you define for the calculated field.

Tip: You can also drag the fields from the editor to the form to let the IDE create visual components for you. This is a handy feature that can save you a lot of time when you’re creating database-related forms.

When you operate on a dataset in Delphi, you can work in different states. These states are indicated by a specific State property, which can assume several different values.

DBGrid.Columns to customize how columns work

Master/detail

Transactions

Error handling: if ComboName.Text = ” then raise Exception.Create (‘Insert the name’);

Datamodule

There are two ways to refer to a record in a dataset: Use a TBookmark/TBookmarkStr to save a reference to the current record, or use the Locate method to find a record that matches given criteria.

To navigate through a dataset, you can use First/while not EOF/Next. Remember to use DisableControls/EnableControls to speed things up when going through a lot of records. An even better method is to let the SQL server do most of the work.

To make changes to each record, use a “while not EOF” loop that contains a call to dataset.Edit, mycolumn.Value=, dataset.Next (Next means that the change will be posted).

Here’s how to fill a regular combobox with stuff from a dataset:

//Here, SELECT data from the database
cds.Open;
while not cds.Eof do begin
    ComboName.Items.Add (cdsName.AsString);
    cds.Next;
end;

When is UpdateSQL required? Typically, TQuery and like query components only allow you to specify a Select statement and it then figures out from that how to build insert, update, and delete statements. But this ability is fairly limited, it does not take much to write a Select statement that it cannot deal with (joins, sub-selects, unions, etc). In this case, the TQuery is read-only. Corresponding TUpdateSQL components allow you to specify the insert, update,  and delete statements corresponding to such selects.

Dataset.Edit/Post

Dataset.InsertRecord ([ComboName.Text, EditCapital.Text, ComboContinent.Text, EditArea.Text, EditPopulation.Text]);

Other stuff

Just like Microsoft development tools, for historical and technical reasons, Delphi provides different ways to connect to a database. You should choose a solution depending on how big the database is, and whether you have the luxury of choosing a specific database engine or the application must be database-agnostic:

  • Direct, database-specific connectors (Interbase Express/IBExpress/IBX for Interbase, or FIBPlus/UIB/IBObject for Firebird, MySQL, SQLite, etc.)
  • BDE (deprecated)
  • dbExpress (ex-DataSnap Direct), which connects to a DB-specific driver; Lighter, faster than BDE
  • goDB (ex-ADOExpress)
  • DataSnap (ex-MIDAS) for n-tier access, or MyBase (ex-Briefcase) for local, XML-based, non-SQL access. Both are based on TClientDataset

As of 2008, the recommended choice is either DB-specific connector or dbExpress.

Overview

Basically, if you need DB-agnostic solutions, use either ADO or dbExpress. If you don’t mind being tied to a given DB engine, use DB-specific solutions like connectors to SQLite, MySQL, FireBird, etc.

BDE

Historically, the first means offered by Delphi to connect to a database was the IDAPI(Independent Database Application Programming Interface). As it never acquired the popularity of Microsoft’s ODBC, it was turned into BDE (Borland Database Engine).

The BDE uses a collection of DLL’s, each one specific to the database that the application wants to connect while presenting a common API to the application:

Data (local or remote) < Database engine (BDE, etc.) < Dataset < Datasource < DB* visual components

Until 1997, BDE was the only way for Delphi applications to connect to database, but it fell in favor because it’s a bit heavy to deploy, and doesn’t offer good performance over remote connections

The BDE has a long and glorious history. It originated in Delphi 1 as an engine for accessing Paradox databases and was later part of the ISAPI initiative involving IBM, Novell, and WordPerfect. Despite a few problems, the BDE is one of the reasons for Delphi’s success in the database arena and, having reached version 5, it is a mature technology.
 
So why move away from the BDE? Deploying it on rented Internet servers is often impossible because of ISPs’ concerns about running system-level services on their servers. Although the BDE has been updated to support features like the Oracle 8 object-relational model, some of its features are still bound to its Paradox roots. Another problem is that the BDE includes the entire engine used by Paradox and dBase to access data. There is no way to deploy a thin version of the BDE excluding Paradox support if you are targeting only SQL servers. (On the other hand some of these problems, such as running SQL Server on an ISP’s server, apply to using ADO as well.)
 
The BDE also does local caching but won’t allow you to interact with it. However, a few Delphi programmers have learned to use the ClientDataSet component to operate on cached data.
 
Despite being freely distributed with Borland�s popular line of application development tools, the BDE was unpopular because of complexities in installation and poor performance. As Delphi became one of the leading application development tools for the Windows platform, individuals and companies proposed alternative interfaces to the BDE. These �BDE Alternatives� optimized access to the database by directly using the native database driver, providing performance and feature advantages with respect to the BDE.
 
The common denominator for database access in Delphi is no longer the BDE. Instead, it’s the TDataset class.
 
TTables = Delphi’s desktop database components; Inefficient in a client/server environment.
 
The reason there is both a TTable and a TQuery component is due to the fact there table-oriented databases like Dbase, Paradox, or Access, and there are set-oriented databases like Interbase, Oracle, and MSSQL.
 
Delphi’s database architecture has not changed significantly since Delphi 3 introduced the abstract TDataSet class to make custom datasets fully integrated with the dataset/data-aware architecture, that up to Delphi 2 was tied only to the BDE datasets.
 
From D3 onwards all BDE functions were removed from TDataset making it independant of any DB format.
 
What TDataset isn’t – TDataset has no:
  • SQL support
  • DB session control functions
  • inherent links to any DB
  • No index support
  • No range setting
  • No master-detail linking

(From D2007 PDF) “TUpdateSQL Lets you use cached updates support with read-only datasets.

Connecting to another dataset. Client datasets can work with data provided by another dataset. A TDataSetProvider component serves as an intermediary between the client dataset and its source dataset. This dataset provider can reside in the same data module as the client dataset, or it can be part of an application server running on another machine. If the provider is part of an application server, you also need a special descendant of TCustomConnection to represent the connection to the application server.

Client datasets provide the most robust way to work with cached updates. By default, other types of datasets post edits directly to the database server. You can reduce network traffic by using a dataset that caches updates locally and applies them all later in a single transaction. For information on the advantages of using client datasets to cache updates, see Using a client dataset to cache updates

Client datasets can apply edits directly to a database server when the dataset is read-only. When using dbExpress, this is the only way to edit the data in the dataset (it is also the only way to navigate freely in the data when using dbExpress). Even when not using dbExpress, the results of some queries and all stored procedures are read-only. Using a client dataset provides a standard way to make such data editable.

In addition to these specialized client datasets, there is a generic client dataset (TClientDataSet), which does not include an internal dataset and dataset provider. Although TClientDataSet has no built-in database access mechanism, you can connect it to another, external, dataset from which it fetches data and to which it sends updates.

Typically, an application checks the dataset state to determine when to perform certain tasks. For example, you might check for the dsEdit or dsInsert state to ascertain whether you need to post updates.

dbGO/ADO Express

If you don’t mind depending on Microsof’s MDAC layer, you can use the ADO page of components

ActiveX Data Objects (ADO) is part of Microsoft’s Universal Data Access initiative. It provides a simplified framework for data access based on OLE DB, the real power horse behind the scene. Programming directly for the OLE DB layer is complicated so Microsoft has provided a simpler solution.
 
In providing the ADOExpress technology in Delphi, Borland has accepted ADO as a common technology and has also acknowledged Microsoft’s Access as a widespread database engine. Just as the BDE includes some Paradox-related features, ADO includes several features which are more Access-oriented than a universal data access solution should provide.

dbExpress/DBX/DataSnap Direct

Otherwise, you can use dbExpress, which offers very good performance because it’s unidirectional. This means that you’ll need to use a ClientDataSet component (located in the Data Access page) to navigate through a cache and be able to use DB* visual components. Components in the Data Access page can be used with any data access solution, and include TClientDataset, which can work with data stored on disk or, using the TDataSetProvider component also on this page, with components from one of the other groups.

Note that in recent version of Delphi, dbExpress’ TSQLClientDataset was replaced by TSimpleDataset, which is meant for two-tier architectures. TSimpleDataSet is really the combination of TDataSetProvider + TClientDataSet. To update the SQL database, use the ClientDataSet’s ApplyUpdates(), that you can call in the DB-control’s AfterPost event.

Database > dbExpress driver > TSQLConnection > TSQLDataSet > TSQLDataSetProvider > TClientDataSet > TDataSource > DB* visual components

Realizing the limitations of the BDE, Borland proposed a new type of database interface called dbExpress. This interface was designed to broker access between Delphi and virtually any relational database through 3rd party drivers. Borland significantly improved the performance of dbExpress with respect to the BDE, but the implementation was buggy and supported only a limited subset of SQL that hampered functionality.
 
dbExpress – a.k.a. DataSnap Direct – is Borland’s new cross-platform data access layer. Does dbExpress allow access to file based databases such as DBase, Paradox and FoxPro? No. It currently works with DB2, Interbase, MySQL and Oracle.
 
Unlike the BDE, dbExpress returns only unidirectional cursors and therefore does no caching. The MIDAS ClientDataset can be used for caching, and scrolling, indexing, and filtering on the result set.
 
In 2000, Borland introduced a new SQL driver architecture called “dbExpress.” dbExpress is designed to deliver ultra high performance data access and simplify deployment and configuration of SQL drivers. dbExpress is a pure SQL driver architecture and does not use BDE technology. This new driver architecture replaces the SQL data access functionality of the “older” BDE SQL Links combination, but does so without the runtime and deployment overhead of the BDE. Developers have the option of using either InterBase Express (IBX) or dbExpress to access local InterBase tables.

DataSet

Table, Query, StoredProc

ClientDataSet/MyBase

“The ClientDataSet component ships with the Client/Server and Enterprise editions of Delphi and C++ Builder. This component, which can be used in place of other DataSet components, permits for the reading and writing of single user flat files. The ClientDataSet component relies on a 150K DLL named DBCLIENT.DLL, but does not make use of the BDE.”

Database-specific solutions

If you have the choice of database and don’t mind making your application database-specific, you can use some library that connects to the database directly (MySQL, SQLite, Interbase Express/IBExpress/IBX or FIBPlus/UIB/IBObject for Firebird, etc.)

If you’re accessing Microsoft SQL Server or Access databases, you’ll probably prefer to use ADO. If you’re using Paradox or InterBase, then the BDE is probably still the best bet — unless you’ve boarded the InterBase Express.
 
Generic client-to-database layers like the BDE, ODBC, dbExpress and ADO hide most of the capabilities of transactional database engines, flattening connectivity to a generic “lowest common denominator”.
 
Powerful server databases like InterBase/Firebird and Oracle are made to conform to the behaviors of desktop databases like Paradox or dBase. It takes heavy layering of client and middleware driver code between the user and the database to accomplish this flattening, while disabling essential capabilities of the server databases’ engines. Since everything in InterBase/Firebird happens inside transactions, this approach essentially kills most of the benefits of using client/server for networking mission-critical applications. IBO cuts right through all this and connects its data access objects directly to the application programming interface (API) of the InterBase/Firebird engine. From the start IBO freed itself from the restrictions of TDataset and its limiting, local database oriented memory model.
 
One of IBO’s significant benefits is that its native data access architecture is built from TComponent up. This means you you can harness the full power of IBO without the TDataset architecture that Borland provides. What this means in terms of software investment is that you can use IBO with the standard version of Delphi – VERY cheap compared to the Professional and Enterprise versions.
 
The ZeosLib is a set of database components for MySQL, PostgreSQL, Interbase, Firebird, MS SQL, Sybase, Oracle and SQLite for Delphi, FreePascal/Lazarus, Kylix and C++ Builder.”

MyBase

And if you only need a local database (ie. no connection over the network), and the amount of data is small, check out MyBase (ex-MIDAS). It only required midas.dll, and a ClientDataSet to handle data in RAM

MIDAS/DataSnap

“With MIDAS (Multi-Tier Distributed Application Services), your VCL-based client application receives data over a TCP/IP connection or through the use of sockets. The data is provided by an application server, which you also write using Delphi. While the application server does make use of the BDE, the client application does not. Client applications created using MIDAS are often referred to as thin clients, since they require less configuration and fewer files (specifically, no BDE).”

“MIDAS (DataSnap) is needed with DbExpress, at least if you want to present data in a GUI. MIIDAS is optional with IBX and not really needed with the ADO components. Think of DbExpress + MIDAS as the “new” BDE.”

How does Delphi work with database engines?

  1. You build the UI with DB-aware components like DBGrid or DBNavigator that share a common datasource
  2. The datasource is a conduit to…
  3. a dataset, which contains a set of records from a database, read from either a single table or multiple tables through a SQL SELECT:
    • A BDE dataset uses TTable, TQuery, TStoredProc
    • An ADO dataset uses TADODataSet, TADOTable, TADOQuery, or TADOStoredProc
    • A dbExpress dataset uses TSQLDataSet, TSQLTable, TSQLQuery, or TSQLStoredProc
    • An Interbase dataset uses TIBDataSet, TIBTable, TIBQuery, or TIBStoredProc
    • Specialized client datasets such as TBDEClientDataSet, TSimpleDataSet, or TIBClientDataSet are also available
  4. Each type of dataset uses a different connection component to actually access the DB engine:
    • A BDE dataset uses the TDataBase object
    • An ADO dataset uses TADOConnection
    • An Interbase dataset uses TIBDatabase
    • A dbExpress dataset use TSQLConnection. As explained above, since dbExpress datasets are always read-only and unidirectional, you can only navigate by iterating through the records in order, and you can’t use the dataset methods that support editing. Also, unidirectional datasets can only supply a single record at a time      
    • Specialized datasets require an appropriate type of connection
  5. Finally, the connection component connects to the actual database, either file- or server-based.

Data module = Data source + Dataset + Connection

Database components are globally available within your application. In other words, so long as your Database component appears on an auto-created form, or appears on the main form, it is available to all forms and data modules in the application, without the need for a corresponding uses clause statement.

    What is TDataset?
    A virtual dataset for accessing a database. Encapsulates the mechanisms for linking a DB to data-aware controls and sending data To/From the DB. Conceptually data is handled in table form – each row required is buffered internally. Columns are represtented using Fields.
     
    A dataset is the fundamental unit for accessing data is the dataset family of objects. Your application uses datasets for all database access. A dataset object represents a set of records from a database organized into a logical table. These records may be the records from a single database table, or they may represent the results of executing a query or stored procedure.
     
    The state – or mode – of a dataset determines what can be done to its data. At runtime, you can examine a dataset’s read-only State property to determine its current state.
     
    To read or write data in a dataset, an application must first open it. You can open a dataset in two ways: Either set the Active property of the dataset to True, at design time in the Object Inspector or in code at runtime (CustTable.Active := True;), or call the Open method for the dataset at runtime (CustQuery.Open;).

Since DataSource components are used primarily for managing the interaction between data controls and DataSets, you rarely need to use a DataSource for data access that is entirely programmatic. In other words, if you have no user interface, you probably do not need a DataSource.

The simplest form of database doesn’t use a database engine, and saves data in a file instead through the MyBase (ex-MIDAS) so that client datasets can save and read themselves to/from a disk; In this case, use the dataset’s SaveToFile() and LoadFromFile() methods, or set the FileName property to make it easier.

There are three basic classes of datasets:

  • Table type datasets represent a single table from the database server. Table type datasets include TTable, TADOTable, TSQLTable, and TIBTable
  • Query-type datasets represent a single SQL command, or query. Query-type datasets include TQuery, TADOQuery, TSQLQuery, and TIBQuery
  • Stored procedure-type datasets represent a stored procedure on the database server. Stored procedure-type datasets include TStoredProc, TADOStoredProc, TSQLStoredProc, and TIBStoredProc

In addition, TDataSet has some descendants that fit into more than one category:

  • TADODataSet and TSQLDataSet  have a CommandType property that lets you specify whether they represent a table, query, or stored procedure
  • TClientDataSet represents the data from another dataset. As such, it can represent a table, query, or stored procedure. TClientDataSet behaves most like a table type dataset, but it also has some of the features of queries and stored procedures: the management of parameters and the ability to execute without retrieving a result set
  • Some other client datasets (like TBDEClientDataSet) have a CommandType property that lets you specify whether they represent a table, query, or stored procedure. Property and method names are like TClientDataSet, including parameter support, indexes, and the ability to execute without retrieving a result set.
  • TIBDataSet can represent both queries and stored procedures. In fact, it can represent multiple queries and stored procedures simultaneously, with separate properties for each.

The ClientDataSet component, which can be used in place of other DataSet components, permits for the reading and writing of single user flat files. The ClientDataSet component relies on a 150K DLL named DBCLIENT.DLL, but does not make use of the BDE.

It is possible to use a specialized client dataset to connect to a dataset; This type of specialized client datasets is a composite component that includes another dataset internally to access the data and an internal provider component to package the data from the source dataset and to apply updates back to the database server. You might want to use a two-part dataset for the following reasons: A client dataset can work reliably with a cache instead of applying changes directly to the database; You can improve performance by running a client dataset on a client PC and a dataset on a server; datasets like dbExpress’ are read-only; TClientDataSet can link to any source dataset, even those that don’t provide a specialized client dataset.

A single connection component can be shared by multiple datasets, or each dataset can use its own connection. Each type of dataset connects to the database server using its own, TCustomConnection-derived type of connection component, which is designed to work with a single data access mechanism:

  • Borland Database Engine (BDE) uses TDatabase
  • ActiveX Data Objects (ADO) uses TADOConnection
  • dbExpress uses TSQLConnection
  • InterBase Express uses TIBDatabase

All database connection components except TIBDatabase let you execute SQL statements on the associated server by calling the Execute method. Although Execute can return a cursor when the statement is a SELECT statement, this use is not recommended. The preferred method for executing statements that return data is to use a dataset. The Execute method is very convenient for executing simple SQL statements that do not return any records. All database connection components maintain a list of all datasets that use them to connect to a database. A connection component uses this list, for example, to close all of the datasets when it closes the database connection.

Useful methods to retrieve metadata from the database server:

  • GetTableNames()
  • GetFieldNames()

Datasets offer navigation and search methods like First, Last, Next, Prior, MoveBy, Bof, Eof, Bookmark, Locate, Lookup, Filter.

Here’s how to have a dataset run an SQL query programmatically:

//The dataset must be closed when you specify or modify the SQL property.
MyQuery.Close;
MyQuery.SQL.Clear;
MyQuery.SQL.Add(‘SELECT CustNo, OrderNO, SaleDate’);
MyQuery.SQL.Add(‘ FROM Orders’);
MyQuery.SQL.Add(‘ORDER BY SaleDate’);
MyQuery.Open;

Since MyQuery is a TStrings, any item can be access and changed:

MyQuery.SQL[2] := ‘ORDER BY OrderNo’;

You can also load an SQL query from file:

MyQuery.SQL.LoadFromFile(‘custquery.sql’);

Here’s how to build an SQL query by providing parameters at runtime:

SQLQuery1.ParamByName(‘Capital’).AsString := Edit1.Text;
INSERT INTO Country (Capital) VALUES (:Capital)

Queries that don’t return a result set should be run by calling ExecSQL:

CustomerQuery.ExecSQL;

If you are executing the query multiple times, it is a good idea to set the Prepared  property to True.

Here’s to modify a record in a dataset:

with CustTable do begin
  Edit;
  FieldValues[‘CustNo’] := 1234;
  Post;
end;

Unlike most datasets, client datasets can also position the cursor at a specific record in the dataset by using the RecNo property. Ordinarily an application uses RecNo to determine the record number of the current record. Client datasets can, however, set RecNo to a particular record number to make that record the current one.

Persistent fields are the fields added to the dataset at design time using the field editor, saved in dfm file and loaded from the resource at runtime. Called persistent because they are not recreated everytime the dataset is closed and re opened.

To check

  • Data module
  • Fields (dynamic/persistent, calculated, data, lookup, aggregate), controlling user input, ADT + array + dataset + reference fields
  • If the datasets TTable and TQuery can be used without the BDE (SQLite)… when does their use require the BDE?
  • Sessions
  • Master/details

How to do this?

  • Display a single record vertically, ie. grey header on the left, and data on the right?
  • Let the user make any change in the data-aware grid, and save changes by just clicking on Save, or cancel through Close/Cancel, while checking that all changes are OK before validating input?
  • How to combine ID + label (eg. product ID + description from table Products) in a combo box?
  • How to provide up/down or left/right arrows to move from either one part of a record to another (when all columns don’t find in grid) or from one SELECT to the other (eg. when viewing all the orders for a given customer using left/right arrows)?

More information

Managing data with FireBird

http://www.destructor.de/firebird/1.5/embedded.htm

“Borland’s Delphi doesn’t seem to work with Firebird 1.5. I just get messages like “Connection to database refused.”

The Windows client library in Firebird 1.5 and higher is named fbclient.dll and is located in Firebird’s \bin directory. Anything Made in Borland expects a client library named gds32.dll located in the system path. You’ll need to generate a special version of the Fb 1.5 Windows client library that is named gds32.dll and contains a version string recognised by Borland products. If you choose the “compatibility” option during the installation, this library will be generated for you and placed in the \bin directory, ready for you to copy over to your system directory.

If you didn’t take the compatibility option during install, you can generate the special client yourself using the utility program instclient.exe (also in \bin). The doc for it is in \doc\ README.Win32LibraryInstallation.txt.”

What package to get? http://www.firebirdsql.org/index.php?op=files or http://prdownloads.sourceforge.net/firebird/

Managing data with Firebird embedded

More information here.

Managing data with SQLite

More information here.

Other engines

Handling errors using exceptions

Debbuging tools and tips:

An exception is an alternative way for a function to report the outcome of its operation. Not all functions and packages support exceptions, though. Here’s some pseudo-code:

If MyFunc() = False then begin
    ShowMessage(‘MyFunc failed’);
    Exit;
end;

or

try
    MyFunc();
except
    ShowMessage(‘MyFunc failed’);
end;

There are two kinds of exceptions: try..finally blocks, and try..except blocks. Typically, you use try..finally blocks to protect resources, and try..except blocks to handle exceptions. Try/finally are much more used than try/except, as the former is an easy way to avoid memory leaks by making sure you release any resource dynamically allocate, regardless of the outcome.

If you just want to run some code that could trigger an exception, use the following:

try
    //stuff that could trigger an exception
except
    //Handle exception
end;

If you don’t want to handle an exception, but make sure to free a resource that you allocated before running the code likely to bomb, use this:

AllocateResource
try
    //stuff that could trigger an exception
finally
    //Free resource
end;

If you want both to handle an exception and perform some tasks even when things went ok, you’ll have to run the following structure with a second try embedded (Delphi doesn’t provide a single try/except/finally structure):

AllocateSomeResources;
try
    try
        //stuff that could trigger an exception
    finally
        //perform general actions, such as FreeAndNIL()
    end;
except
    //handle exception
    on E: Exception do begin
        MessageDlg(E.Message, mtWarning, [mbOK], 0);
    end;
end;

This could be layed out differently:

AllocateSomeResources;
try try
    //stuff that could trigger an exception
finally
    //perform general actions, such as FreeAndNIL()
end; except
    //handle exception
    on E: Exception do begin
        MessageDlg(E.Message, mtWarning, [mbOK], 0);
end;

You might wonder why a resource is allocated before instead of inside a try block. The reason is that, when we call a constructor, we are assured that either the call succeeds and we get a valid object, or the call fails and all resources are released. This is why we can place a constructor right before a try..finally block – if the constructor raises an exception, there will be nothing to free.

If you only want to catch an exception but actually have it handled elsewhere (eg. centralizing it), use the Raise() function:

Result := SomeResource.Create;
try
    Result.TrySomething;
except
    Result.Free;
    raise; //Let error bubble up and be handled elsewhere up there
end;

An alternative is to attempt to create an object, and use a Try/Finally to Free the object: In case the object couldn’t be created in the first place, Delphi will jump to the nearest exception handler, and the Finally section is ignored entirely:

Strings1 := TStringList.Create;
try
    Strings1.Add(‘Hello, world!’);
finally
    Strings1.Free;
end;

From Exception Handling for Fun and Profit (a.k.a. Exception Handling in Delphi) by Nick Hodges: “One of the main purposes of exception handling is to allow you to remove error-checking code altogether and to separate error handling code from the main logic of your application.

One way to do that is to centrally handle exceptions. TApplication has an event that allows you to do just that � the OnException event. You can use this event to deal with all exceptions of any type that aren’t otherwise handled by your application. You can use this event to log your exceptions, or provide specific handling for specific types of exceptions.

With exception handling, you can write your code as if nothing ever goes wrong, and then wrap that code up with try�except blocks if you like to deal with any of the errors and problems that may occur. This enables your code to run more efficiently, as it isn�t constantly checking parameters and other data to make sure that it is in the proper form before doing anything with it.”

“As noted above, you should never eat exceptions. What you should do instead is to trap only specific exceptions that might reasonably be expected to occur in your code.

As I mentioned above, I see code that eats exceptions added because the developer (or manager, or someone not thinking very clearly) never wants the user to see any errors. The way to deal with that is to trap the specific exception that the user is seeing. For instance:

try
  SomeCodeThatRaisesAnEConvertError;
except
  on E: EConvertError do begin
  // Deal with this specific exception here
  end;
end;

Furthermore, database exceptions (and some others, like COM errors) generally include an error code, and you may wish to trap only errors with a certain error code and allow others to surface.  You can do this as follows:

try
    SomeCodeThatRaisesAnEConvertError;
except
    on E: EIBError do begin
        if E.ErrorCode = iSomeCodeIWantToCatch then begin
            // Deal with this specific exception here
        end else begin
            raise; // re-raise the exception if it�s not the one I handle
        end;
    end;
end;

Bottom line: Trap exceptions as far down the class hierarchy as you can and only trap those exceptions that you are planning on handling.


If you are like most of us, when first learning to use exception handling, you are tending to use exception blocks far too much. In most cases you do *not* want to handle every possible exception at every possible place in your code. You *do* however, want to take advantage of finally blocks as often as you can to guarantee against memory and resource leaks.

Perhaps you should consider using Application.OnException to avoid the default dialog box showing. This way you won’t have to catch the exceptions, but you can still avoid them being visible to the end user.

Resources

Components

Note

  • Components come in different shapes, as either a source file (.PAS), a compiled source file (.DCU), a source package that you must compile yourself (.DPK), or a compiled binary file (.BPL, which requires its corresponding .DCP if you want to use it in design mode instead of just at run-time)
  • Most grids are inherited from TDatasets, which isn’t available in the Personal version of Delphi. If using the Personal version, get a so-called unbound grid
  • A grid is just that; a spreadsheet also includes some computing capability, ie. Excel in your app
  • If you get the error “Could not create output file myfile.bpl”, make sure that the output directory exists, as Delphi is not smart enough to create it itself

Tabs

As an alternative to showing multiple forms, you can use a tab control and stick a group of controls in each page of the tab.

Additional > TTabSet

Win32 > TTabControl and TPageControl

From Cantu’s “Mastering Delphi7”:

  • The PageControl component has [TTabSheet] tabs on one side and multiple pages (similar to panels) covering the rest of its surface. There is one page per tab, so you can simply place components on each page to obtain the proper effect both at design time and at run time.
  • The TabControl has only the tab portion but offers no pages to hold the information. In this case, you’ll want to use one or more components to mimic the page change operation, or you can place different forms within the tabs to simulate the pages.

PageControl.Page stores a list of TabSheet objects.

Every time you need multiple pages that all have the same type of content, instead of replicating the controls in each page, you can use a TabControl and change its contents when a new tab is selected.

TTabSet vs. TTabControl vs. TPageCtrl/TTabSheet?

  • TTabControl is used when displaying the same controls on multiple tabs, eg. editing the properties of different objects through the same key/value vertical grid
  • TTabSet
  • TPageControl/TTabSheets/TFrames

Building reports

A report is a form with fields that you fill with data and send to the printer, possibly providing a preview so that the user can see what it’ll look like before actually printing the page.

Report generators let you build forms in two ways: Through a designer at design-time (ie. like drawing forms in the Delphi IDE), or through code at run-time.

FastReports 4 VCL

  • Closed-source, $79-349
  • FastReport�4 VCL is an add-on component that allows your application to generate reports quickly and efficiently. FastReport� provides all the necessary tools to develop reports, including a visual report designer, a reporting core, and a preview window.”
  • FastScript: powerful multi-language script engine. It is useful for developers who want to add scripting abilities to their projects
  • FastQueryBuilder: Visual SQL query builder. It allows complex query creation based on several data tables without having to learn the SQL language
  • User’s Manual (to work within the Designer application), Programmer’s Manual (to work from the Delphi application), and Developer’s Manual (to create custom objects and function libraries for FastReport) are available here

the developers manual as to how to create custom objets and function libs for fr.

If you don’t have the installer, here’s how to install FastReport 4 manually:

  1. Unzip the package
  2. Add the following directories to the Delphi IDE:

    FastQB
    FastScript
    ExportPack
    Source
    Source\ADO
    Source\BDE
    Source\DBX
     
  3. Compile all the *.bdsproj file in the different directories
  4. In addition, all the project files that start with “dcl” are design-time components, so they also need to be installed (Right-click on the project, choose Install, then close the project)

    Note: The Source\FIB\dclfrxFIB11.bdsproj requires the commercial FIBPlus component. Compiling this project will fail otherwise

Several demo projects in… \Demo.

The Text object can also include tags that will be converted at run-time: “Hello, World! Today is [DATE].”

A Band is used to place a group of objects at a specific location in a page. Use File > New Report to start with a three-band page. Bands are useful to add recurrent occurences such as headers and footers.

Reports can be scripted (Pascal, C++, Basic, JScript), so you don’t have to do this from the application.

Charts can be added through the TfrxChartObject component based on the TeeChart library which comes with Delphi.

FastReport provides extensive support for fetching data from databases, using ADO, BDE, IBX, etc.

If you need, you can add dialog boxes in a report (File > New Dialog), so you can eg. display some warning before printing a report, or prompting the user to provide some data through an inputbox.

Here’s how to build a basic, one-page report at design-time to show a barcode, fill it with data at run-time, display a preview version, and let the user send it to the printer:

  1. Create a new VCL project
  2. Open the FastReport tab, and drop a TfrxReport control onto Form1
  3. Drop a TfrxBarcode as well
  4. Double-click the TfrxReport to start the Designer
  5. In the palette on the left side, add a Text object (for the description) and a Barcode object
  6. File > Save to save the design-time file. By default, the report will be saved in the form’s DFM file. Close the Designer
  7. Back in Delphi, add a push button, and add the following code to fill variables with data, display the Preview dialog to let the user check that it looks OK and then send the job to the printer:

    frxReport1.ShowReport(); 

ReportBuilder

QuickReports

Rave Reports

Ships with Delphi, but maybe it’s a limited version compared to the one available from www.nevrona.com. As of August 2009, the site is not well maintained (nothing in News, empty page when clicking on Features, etc.).

A Rave project than hold more than one report, and each report can have one or more pages. Leonel Togniolli wrote a four-part series of articles as an Introduction to Rave Reports. The reports can either be an external file, or embedded in the EXE.

Here’s how to create a report using Rave 7.5.2 that ships with Delphi2007, and allow the user to push a button to fill the report with data and send the page to the printer:

  1. Create a new VCL project
  2. From the Rave tab, drop a TRvProject in the form. This is the connection between your application and the the report that we will produce below
  3. (optional) You can add a TRvSystem and link it to the RvProject control through its Engine property. RvSystem is responsible for the general configuration of the reports (which printer to use, the margins, etc.)
  4. Double click the RvProject control
  5. In the Designer window, add a text widget
  6. Hit F9 to check that it works
  7. Save the project file and close the Designer
  8. Back in Delphi, change RvProject.ProjectFile property to point to this Rave project file
  9. Add a pushbutton on the form to call RvProject1.Execute()

Here’s how to add parameters to the project/report/page and set them from the Delphi application:

  1. Open the Rave Designer application
  2. Select the report in the treelist on the right
  3. Open the Parameters item
  4. Add “Name” as a parameter, and close
  5. From the Report tab, add a DataText control, change its DataField property (Project Parameters) to link it to the Name variable that we just created. Click on the Insert Parameter button, and OK
  6. Close the Designer, and go back to the Delphi IDE
  7. Modify the ButtonClick event thusly:

    RvProject1.Open;
    RvProject1.SelectReport(‘ParametrizedReport’,False);
    RvProject1.SetParam(‘Name’,’Leonel’);
    RvProject1.Execute;
    RvProject1.Close;

Post-Initialize Variables are those, like number of pages, that are only available after a report has been pre-processed and is ready to be printed.

It’s obviously also possible to have the reporting tool connect to a database, and fill variables with this data.

Elements common to multiple pages or reports can be put in a Global page.

A section, a.k.a. Mirror, is a collection of components, eg. a header with a title, page number, date and time of print, etc.

Rave also supports conditional printing.

Printing barcodes on labels

Here‘s the goal. The barcode will be read by an ANL-810 scanner, which supports multiple coding standards including Code 39, Code 32, CIP39, Code Bar (CLSI), EAN-13 UPC-A, EAN-8, Code 128 (EAN 128), etc.

Note that Code 39 doesn’t support lower case letters and many other characters. Code 39 is a good barcode to start with, because it’s easy and doesn’t require any checksum calculations. If you need characters that can’t be provided by Code 39, try Code 128 B. That gives you the entire printable ASCII set. You’ll need to generate a checksum, and you’ll need to map the codes to characters if you’re using a font – it might be easier to generate as pure graphics. That’s why the ActiveX controls are so popular.

“I suggest Fast Report the best Report tool I have used. I have used QuickReport, Fortes Report, Report Builder and Rave before Fast Report.”

“I use Fast Reports to print my barcodes. it has built in barcode support which makes it pretty easy to use”

ReportBuilder Pro is a very good report generator for adding printing capabilities to your program.”

Free 3of9 Font

http://www.barcodesinc.com/free-barcode-font/

Online Barcode Generator

http://www.barcode-soft.com

TBarcode

TurboPower SysTools

  • http://tpsystools.sourceforge.net/
  • Open-source; Packs a bunch of stuff that has nothing to do with barcodes (“SysTools is a library of utility routines &amp; classes for Borland Delphi, C++Builder, &amp; environments that support COM. It includes 1-D &amp; 2-D bar codes, sorting, money routines, logging, high-precision math, a run-time math expression analyzer, &amp; much more.”)
  • “Turbopower Systools (there is an updated version of Systools floating around in the forums that included D2007 and D2009 support. Check over at Sebastian’s site, he  has been been hard at work updating the TurboPower libraries and doing a great job :)”

Barcodes for Delphi

Han-Soft Barcode VCL

Planner

TMS Software DBPlanner

http://www.tmssoftware.com/site/dbplanner.asp

DevExpress ExScheduler

http://www.devexpress.com/Downloads/VCL/ExScheduler/

ShorterPath Planners

http://www.shorterpath.com/products/planners/

InnovaSoftware Calendar Works

WYSIWYG edit widget

Here are some components you can use if you need to add a WYSIWYG editor in a Delphi application. Some come as VCLs, others as C-DLLs or COM-DLLs. Some support HTML, others use RTF (ie. you can embed pictures in the file, but those controls typically don’t support Hx tags, etc.). Note that with the introduction of IE 5.5, Microsoft’s DHTMLEdit component has been superseded by the MSHTML Editor:

  • Purposesoft HTMLEdit (VCL, single user license E129)
  • WPCubed WPTools (VCL, commercial, HTML)
  • Profgrid DHTMLEdit (VCL access to the MS DHTML edit control OCX that comes with IE, E80 without source code)
  • TRichView (VCL, single user license E189)
  • LMD RichPack (VLC, single user E39, RTF)
  • Terra Informatica HTMEngine (No wrapper for Delphi, “HTMEngine is a native Windows API DLL (dynamic load library). Initially it was designed as a replacement for RichEdit but now it does a lot more. You can use HTMEngine not only as a builtin WYSIWYG HTML editor but also as “HTML layout manager” and print processor”, $350 per developer)
  • TDHTMLEdit (Wrapper around the MS DHTML OCX, failed to run with “[Fatal Error] dhtml.pas(44): File not found: ‘mshtml_tlb.dcu'”)
  • XStandard XHTML WYSIWYG Editor (comes in free Lite, and commercial versions; ActiveX control; 10-user license $179)
  • Think HTML Editor Control (ActiveX control, single developer license $249)
  • Namo ActiveSquare (ActiveX, Full Version from $995.00)
  • HTML Xpress (ActiveX,  single license – 1 server 5 domains license $449)

HTML Viewers

Those only display HTML:

Here’s how to display some HTML in a TRichView widget:

  1. First, install the designtime- and runtime- packages, and add a TRichView and a TRVStyle widgets to a form
  2. Next, add the following code

      RichView1.Style := RVStyle1;
      RichView1.AddNL(‘Hello World!’, 0, 0);
      RichView1.Format;

The way TRichView works, applying a different style to a string requires first making the change to its linked TRVStyle widget via its RVStyle1.ParaStyles property, and then send a string to be formatted.

HTML Cleaners

  • Jeffrey Pohlmeyer’s wrapper (requires libtidy.dll)
  • TLibTidy is a Pascal wrapper for the library version of the HTML Tidy program by Dave Ragget. In opposite to Jeffrey Pohlmeyer’s wrapper all functions are loaded dynamically. A TidyLib.dll is not required until a TLibTidy object is actually created, so your application may also work if the Tidy Library is not available.” (As of 2005, the library is tidy.dll, so this wrapper most likely doesn’t work)
  • TidyCOM – A COM Wrapper for HTML Tidy by Andr� Blavier (“Unfortunately, I am no longer able to maintain TidyGUI and TidyCOM. However, notice that the HTML Tidy core software is still well alive (see the Tidy Source Forge project). TidyGUI and TidyCOM (based on the 4th August 2000 version of HTML Tidy) will still be available from this site as long as necessary.”)

Outlook Bar

To build the familiar vertical bar in MS Outlook:

Grid

As of April 2005, recommended grid widgets are GridView, Profgrid, TMS TAdvStringGrid, Virtual Treeview, SMDBGrid, and ExpressSpreadSheet if you have the dinero. Here are some solutions I found of VCL grid widgets under active development, DB- and non-DB aware:

Here’s a possible check-list:

  • VCL, so as to avoid DLLs or OCXs
  • Size of resulting EXE (empty application no bigger than 1MB)
  • Editable
  • Supports functions (poor man’s Excel)
  • Price
  • Can print as easily as Grid.Print
  • Column auto-sizing
  • Column sorting by clicking on header
  • Column merging
  • Column re-arranging by drap and drop
  • (Double-)clicking on a row selects the entire line
  • Flat and hierarchized rows (main row, sub-rows)

As a reference, here’s the size of an EXE built with Delphi 7 Enterprise to contain just a grid (make sure you clean up the Uses line in the PAS file when replacing one grid with another…):

  • Berg GridView 620KB
  • Virtual TreeView 750KB
  • DbAltGrid 770KB
  • SMB 780KB
  • ProfGrid 930KB
  • TopGrid 950KB
  • TMS TAdvString 1MB
  • DevExpress/ExpressQuantumGrid Suite (too pricey, not tested)

Borland’s TValueListEditor

This is a two-column grid that you can use to display/change “key=value” tuples:

for i := 0 to ASQLite3Query1.FieldCount -1 do begin
    FieldName := ASQLite3Query1.Fields[i].FieldName;
    KeyVal := Format(‘%s=%s’,[FieldName,ASQLite3Query1.FieldByName(FieldName).AsString]);
    ValueListEditor1.Strings.Add(KeyVal);
end;

Scalabium SMDBGrid

  • SMComponents group at Yahoo
  • http://www.scalabium.com/smdbgrid.htm
  • Freeware with sources, currently under development
  • Requires BDE; TSMDBGrid is a data-aware grid only. You can’t use this grid without linked database
  • To install: Close all projects, File > Open the DPK (eg. sources\SMCmpntD7.dpk), compile, install, and either copy the DCU into Delphi’s Library Path per what is says under Tools > Env’t Options, or add the directory to this parameter

    “c:\Program Files\Borland\Delphi7\Projects\Bpl\..”
     
  • Couldn’t find any infos on how to add data (demos load data automagically)
  • To print the grid you may use the TSMPrintData component: http://www.scalabium.com/smr
  • Column auto-resizing is available through the eoAutoWidth flag in ExOptions
  • SMDBGrid can draw the arrow for sorting (like Explorer) but real data sorting must be implemented on dataset level (change the active index for table or ORDER BY clause for query)
  • Use the SMImport (http://www.scalabium.com/smi) for data loading from external file

Here’s how to add and work with SMDBGrid:

  1. Launch Delphi, and open the DPK file, eg. SOURCES\SMCmpntD7.dpk. If you already had an older version installed, the Install button is disabled
  2. Add this new directory to Delphi’ Library path
  3. Once installed, click in the palette on the SMComponents tab, and add an SMDBGrid widget to a form

[Fatal Error] Unit1.pas(7): File not found: ‘Calendar.dcu’. Checked that I had the “VCL Source” installed.

No forum for support?

Berg GridView

Moved here.

Kgrid

X-Files X-DBGrid

http://www.x-files.pl

TMS Software

  • http://www.tmssoftware.com
  • Plenty of components available either as stand-alone, or in packs
  • TAdvStringGrid (Single developer license for commercial use with source, updates and support 75 EUR)
  • Grid Pack (Single developer license for commercial use with source, updates and support 120E)
  • Free for use in non-commercial apps (shows some nag text in free version)

To use TMS’ TAdvStringGrid, it’s better to start with Borland’s TStringGrid documentation, since TAdvStringGrid is based on it.

If you need a non-DB-aware editable grid, use TAdvColumnGrid instead: It has all the features of TAdvStringGrid combined with a flexible design-time and run-time management of cell properties, inplace editors, cell print properties, sort style and formatting.

Here are a few actions that you can perform with this control:

procedure TForm1.FormCreate(Sender: TObject);
var
  index : Integer;
begin
  With AdvColumnGrid1 do begin
    Look := glSoft;
 
    //FixedRows := 0;
    FixedCols := 0;
    ColCount := 3;
    //RowCount := 4;
 
    Columns[0].Name := ‘key’;
    Columns[0].Header := ‘mykey’;
    Columns[1].Name := ‘value’;
    Columns[1].Header := ‘myvalue’;
 
    //Make all columns read-only, except the one called ‘value’
    for index := 0 to ColCount – 1 do begin
      Columns[index].ReadOnly := not (Columns[index].Name = ‘value’);
    end;
 
    //Have right-most column fill all available space until scrollbar
    ColumnSize.Stretch := True;
 
    //Can’t use goRowSelect and still let user edit cells
    //Options := Options + [goRowSelect,goEditing];
    Options := Options + [goEditing];
    //As an alternative to goRowSelect and still let user edit cells,
    //change background color on currently-selected row
    
    //Let user resize, and move columns
    Options := Options + [goColSizing,goColMoving];
 
    //Here’s how to refer to columns by their names
    Cells[ColumnByName[‘key’].Index,1] := ‘test’;
  end;
 
end;
 
//Simulate row selecting by changing font and background colors
procedure TForm1.AdvColumnGrid1RowChanging(Sender: TObject; OldRow,
  NewRow: Integer; var Allow: Boolean);
var
  index : Integer;
begin
  with AdvColumnGrid1 do begin
    RowColor[OldRow] := clWhite;
    RowFontColor[OldRow] := clBlack;
 
    RowColor[NewRow] := clHighlight;
    RowFontColor[NewRow] := clWhite;
  end;
end;
 
//When user edits cell, set current row’s font + background colors back to normal
procedure TForm1.AdvColumnGrid1DblClickCell(Sender: TObject; ARow,
  ACol: Integer);
begin
  with AdvColumnGrid1 do begin
    RowColor[ARow] := clWhite;
    RowFontColor[ARow] := clBlack;
  end;
end;
 
//Triggered when users edits a cell
procedure TForm1.AdvColumnGrid1GetEditText(Sender: TObject; ACol,ARow: Integer; var Value: string);
var
  today : TDateTime;
begin
  today := Time;
  Label1.Caption := IntToStr(MyCounter);
  Inc(MyCounter);
end;
//Triggered when user is done editing a cell
procedure TForm1.AdvColumnGrid1CellValidate(Sender: TObject; ACol, ARow: Integer; var Value: string; var Valid: Boolean);
begin
  ShowMessage(‘AdvColumnGrid1CellValidate: ‘ + Value);
end;

Here’s a simpler way to change the background color of every other row to cream white:

procedure TForm1.AdvColumnGrid1GetCellColor(Sender: TObject; ARow, ACol: Integer; AState: TGridDrawState; ABrush: TBrush; AFont: TFont);
begin
  //Ignore Row[0], ie. header
  if ARow > 0 then begin
    if (ARow Mod 2 = 0) then begin
      ABrush.Color := clCream;
      AFont.Color := clBlack;
    end;
  end;
end;

Note that a grid cannot have just a header, ie. fixed, grey row; It must have at least one non-header row, ie. RowCount > FixedRows:

With AdvColumnGrid1 do begin
    ColCount := 1;
    FixedCols := 0;
 
    //Very first row is fixed to show as header
    FixedRows := 1;
    //Must have at least one non-header row
    RowCount := 2;
    //Each column can have a caption and a name
    Columns[0].Header := ‘Col 1’;
    Columns[0].Name := ‘sql_col1’;
    //Useful when looping through StringList to create columns
    Columns[0].ReadOnly := not (Columns[0].Header = ‘Col 1’);
end;

Here’s how to display the content of a column in the currently-selected row:

procedure TForm1.AdvColumnGrid1DblClick(Sender: TObject);
var
  MyID : String;
begin
  With AdvColumnGrid1 do begin
    MyID := Cells[ColumnByName[‘article_id’].Index,Row];
  end;
  ShowMessage(MyID);
end;

Note: Unlike TAdvColumnGrid.GetEditText, TAdvColumnGrid.CanEditCell is called twice when clicking on a cell (but once when moving to a cell through the keyboard, and once again when switching to edit mode through eg. F2). Here’s how to make a column read-only but allow editing for a specific cell depending on the value of another column in this row:

CanEdit

Here’s how to build a two-column grid to display a key=value interface, with the very first column hidden so as to keep a table’s SQL column names alongside their user-friendly equivalent:

With AdvColumnGrid1 do begin
    ColCount := 3;
    
    //Hidden column
    Columns[0].Header := ‘SQL’;
    Columns[0].Name := ‘article_id’;
 
    Columns[1].Header := ‘Key’;
    Columns[1].Name := ‘key’;
    Columns[1].ReadOnly := True;
    Columns[1].Color := clMedGray;
 
    Columns[2].Header := ‘Value’;
    Columns[2].Name := ‘value’;
 
    //Hide “SQL column”
    HideColumn(0);
 
    //Make first row look like a header
    FixedRows := 1;
    RowCount := 2;
 
    Cells[ColumnByName[‘key’].Index,1] := ‘Second_key’;
    Cells[ColumnByName[‘value’].Index,1] := ‘Some dummy value2’;
 
    Look := glStandard;
    ColumnSize.Stretch := True;
    Options := Options + [goEditing];
    AutoSizeColumns(True);
end;

Here’s how to add a TAdvColumnGridcontrol to a form, and fill it with a SELECT from a database:

DevExpress

ExpressQuantumGrid

Here’s how to install DevExpress QuantumGrid Suite 6.38 in D2007:

  1. Add the following paths to the IDE’s Library Paths:

    ExpressLibrary\Packages
    ExpressLibrary\Sources
    ExpressQuantumGrid 6\Packages
    ExpressQuantumGrid 6\Sources
    ExpressDataController\Packages
    ExpressDataController\Sources
    ExpressEditors Library 5\Packages
    ExpressEditors Library 5\Sources
    ExpressExport Library\Packages
    ExpressExport Library\Sources
    ExpressGDI+ Library\Packages
    ExpressGDI+ Library\Sources
    ExpressPageControl 2\Packages
    ExpressPageControl 2\Sources
    XP Theme Manager\Packages
    XP Theme Manager\Sources
     
  2. Compile ExportLibrary\cxLibraryD11.dpk, and compile/instal dclcxLibraryD11.dpk
  3. Compile QG\cxGridD11.dpk and compile/install dclcxGridD11.dpk
  4. Compile DC\cxDataD11.dpk, cxADOAdaptersD11.dpk, cxBDEAdaptersD11.dpk, cxIBXAdaptersD11.dpk
  5. Compile cxEditorsD11.dpk, compile/install dclcxEditorsD11.dpk, compile cxExtEditorsD11.dpk, compile/install dclcxExtEditorsD11.dpk
  6. compile cxExportD11.dpk
  7. compile dxGDIPlusD11.dpk
  8. compile cxPageControlD11.dpk, compile/install dclcxPageControlD11.dpk
  9. compile dxThemeD11.dpk
ExpressSpreadSheet

ObjectSight TopGrid

DbAltGrid

  • http://www.quasidata.com/dbaltgrid.html
  • $149
  • “Did you ever wish of having a grid that lets you display and edit data not as rows and columns, but rather as records? A grid that would allow you to build unique user interface solutions?”

Virtual TreeView

Moved here.

ProfGrid

  • Single-user license w/out source code 78.50E (w/ source code 118.15)
  • http://www.profgrid.com/grid.html
  • (June 2006) Latest version available is for Delphi7/C++Builder 6
  • “ProfGrid is one of the most powerful unbound grids on the market.”

TStringGrid

This is the standard grid object that comes with Delphi7, and only has basic features. If you want a widget that resizes itself automatically to adapt to the width of the items and offers sorting by clicking on a column header, you’ll have to program this yourself.

TListView

This grid also comes with Delphi, can be used in combination with TTreeList or by itself, and looks more modern that TStringGrid. It doesn’t natively support sorting by clicking on an column header, but this can be implemented easily.

Extended StringGrid

TKStringGrid

JVCL

ABF

VCL
  • http://www.abf-dev.com/abf-vcl.shtml
  • “more then 60 components”
  • Contains an enhanced ListView with sorting columns
  • Full version of the ABF VCL one developer license including source $99
  • Any grid in there?
abcComponents

TjanGrid

  • TjanGrid is a TStringGrid descendant
  • (“TjvStringGrid has been renamed to TjanGrid.”)
  • Failed to use after installing in new package (missing stuff)

ElTree Lite 3.20

TXDBGrid

  • TXDBGrid component is the functional extension of Borland’s TDBGrid.”
  • 49E

TExDBGrid

RXLib

Torry Grids

A bunch of grids at Torry, but most too basic and deadware

Woll2Woll Infopower

List of older components

http://www.kobira.co.jp/sakura/d_table.htm

TCRGrid enhanced VCL data-aware grid control

  • http://crlab.com/crgrid/
  • Doesn’t seem to be available as a stand-alone widget
  • Integrates a query system with a regular grid widget

TfzGrid

FlyTreeView

TxDbGrid

Task Pane

This is the alternative to the Outlook bar introduced with XP. At least five widgets are available: (RIP) TEasyTaskBand, Raize TRzGroupBar, TMS TAdvPanelGroup (also available in the TMS Component Pack), DevExpress ExpressNavbar, ??? in the JVCL, LMD BarPack, and (RIP) TBX (add-on package to the Toolbar 2000 package).

Here’s how to work with MustangPeak’s TEasyTaskBand:

type
    EasyTaskBand1: TEasyTaskBand;
    ImageList1: TImageList; //Big icons for groups
    ImageList2: TImageList; //Small icons for items in groups
[…]
var
    Group: TEasyCollectionItem;
    Item: TEasyCollectionItem;
    Group: TEasyGroup;
    Item: TEasyItem;
begin
    EasyTaskBand1.BeginUpdate();
    Group := EasyTaskBand1.Groups.Add;
    Group.Caption := ‘Group 1’;
    Group.ImageIndex := Random(ImageList1.Count);
    Item := Group.Items.Add();
    Item.Caption := ‘Item: ‘ + IntToStr(j);
    Item.ImageIndex := j mod ImageListSmall.Count;
    Item.Captions[1] := ‘Detail 1’;
    Item.Captions[2] := ‘Detail 2’;
 
    Item := EasyTaskBand1.Groups[0].Items.Add;
    Item.Caption := ‘Item: ‘ + IntToStr(Item.Index);
    Item.ImageIndex := 0;
 
    Item := TEasyGroupStored(Group).Items.Add;
    Item := LV.Items.Add;
 
    EasyTaskBand1.EndUpdate();
    EasyTaskBand1.Groups.Clear
    EasyTaskBand1.Groups[0].Bold := CheckBoxSpecialGroup.Checked

If you want a task pane to resize automatically if the user changes the form’s size (eg. going from maximized to some smaller, custom size), set the pane’s Align property from its default alNone to alLeft.

Internet

Here‘s how to fetch a web page and display its HTML source in a memo using ICS’ HTTP client.

Here are some well-known components that support Internet protocols:

  • ICS (open-source)
  • Magenta Systems File Transfer Components comprise three Delphi components, TMagFtp, TMagHttp and TMagFileCopy, the first two of which are high level descendants of the ICS TFtpClient and THttpCli components, all allowing transfer of multiple files and subdirectories with a single function call.

    Magenta Systems File Transfer Components are copyrighted software, but the compiled component DCUs may be used without cost in applications for use by the developer or within their company but which are not otherwise distributed (including freeware and shareware). The component source code may be licensed for a cost of �65 (UKP) (�76.38 with UK tax) which is about $125, or is available without extra cost to anyone that has financially contributed to the development of the ICS SSL version at http://www.overbyte.be or that has licensed Magenta Systems TMagRas component. “
  • Indy (open-source)
  • Synapse (open-source)
  • LibCurl (open-source)
  • TurboPower Internet Professional (open-source; Deadware since 2003)
  • Clever Internet Suite (commercial)
  • MarshallSoft (commercial)

To read

Creating objects at runtime

If using “nil” as the owner, you must call the Free() method or you’ll get a memory leak.

You don’t have to use a variable to hold the pointer to the instance (source):

with TTimer.Create(Self) do begin
   Interval := 1000;
   Enabled := False;
   OnTimer := MyTimerEventHandler;
end;
//Do NOT call Free with try/finally!

or

with TTable.Create(nil) do
try
   DataBaseName := ‘MyAlias’;
   TableName := ‘MyTable’;
   Open;
   Edit;
   FieldByName(‘Busy’).AsBoolean := True;
   Post;
finally
   Free; //If using variables, you can call FreeAndNil() instead
end;

… but it’s recommended to use a variable, so you can refer to it later:

FTimer := TTimer.Create(Self) ;
 
if not Assigned(FTimer) then do begin
    ShowMessage(‘Not assigned’);
    Exit;
end;
 
with FTimer do begin
   Interval := 1000;
   Enabled := False;
   OnTimer := MyInternalTimerEventHandler;
end;
FreeAndNil(FTimer);

Alternatively:

FTimer := TTimer.Create(Self) ;
try
    with FTimer do begin
       Interval := 1000;
       Enabled := False;
       OnTimer := MyInternalTimerEventHandler;
    end;
finally
    //Since Delphi doesn’t provide try/expect/finally, here’s a way to check for errors
    if not Assigned(FTimer) then do begin
        ShowMessage(‘Failed creating Timer’);
    end else begin;
        FreeAndNil(FTimer);
    end;
end;

Resources

Displaying different sets of objects in a form

If you’d rather not use several forms to show sets of objects, two alternatives are available: Using a TPageControl, and using frames.

TPageControl

Use a TPageControl to host the different pages, hide them all, and only display the desired page when the user selects the item in a menu.

Frames

Create frames, and insert the desired frame in the main form at runtime

Resources

Displaying a lot of fields

If your application connects to a SQL server, it will have to display and handle a lot o fields that users can edit and save. Here are ideas proposed by experienced developers:

  • Use the TPageControl which allows you to tab through pages on the same form, using Next/Prev buttons to move through pages
  • TabControl
  • Use a TScrollBox to scroll horizontally and vertically if needed

TabControl vs. PageControl? “Use TTabControl to add a control with multiple tab settings to a form. Unlike a page control, TTabControl is not made up of several pages that contain different controls. Instead, TTabControl is a single object. When the current tab changes, the tab control must directly update its contents to reflect the change in an OnChange event handler. (CLX?) TTabSheet is an individual page in a TPageControl object.

Use TPageControl to create a multiple page dialog or tabbed notebook. TPageControl displays multiple overlapping pages that are TTabSheet objects. The user selects a page by clicking the page�s tab that appears at the top of the control. To add a new page to a TPageControl object at design time, right-click the TPageControl object and choose New Page.

To create a tabbed control that uses only a single body portion (page), use TTabControl instead.”

Microsoft Inductive User Interface Guidelines

Delphi.Net

To speed it up:

  1. Register with Borland, and download hotfixes
  2. Install DelphiSpeedup
  3. Make those changes
  4. “The installation should have created a shortcut named “Delphi for Microsoft Win32″ in its program menu entry. Use that to start BDS with only the Win32 Delphi personality loaded. That will already speed up the load time. If you have not done so yet install the update 2 you can download from the registered users site. The BDS Welcome page has a link to that on the lower left.”
  5. “You can disable component packs you do not need using the Components->Install packages dialog, just uncheck the design-time packages you do not need and don’t forget to check the “Default” checkbox on the lower left of the dialog before you OK it.”
  6. “You can even create a custom installation to exclude things you don’t need. See http://homepages.borland.com/medington/DelphiStartupTimes.htm There are a number of unofficial hotfixes available as well that replace some of the standard IDE packages. They were originally posted on blogs by Borland people (e.g. http://blogs.borland.com/abauer ), but I think the registered users site lists them as well now.”

Glossary

BDE

Borland Database Engine for database access

BPL

“Borland Package Library”; Delphi-specific, enhanced DLL

CLX

Borland CLX� (Component Library for Cross-platform) library, which encapsulates the Qt widget set for Windows and Linux.

DataSnap

ex-MIDAS; Middleware

dbExpress and ClientDataSet

To create database apps

DCP

“Delphi Compiled Package”; Contains headers and symbols when compiling a DPK. Must be provided with a BPL for design-time packages.

DCU

Unit in compiled format. All DCUs are combined into a single EXE, with the possible addition of VCLs if you prefer that components be compiled into the EXE instead of as DLLs.

DFM

A file describing a form, its properties, and its components

DPC

“Delphi Package Collection” = bunch of BPLs in one file?

DPK

Delphi package project file

DPR

Delphi project file

ECO

ECO is the .Net version of Bold which was already available in Delphi 7. ECO lets you build a .Net application from an Object model, regardless of whether the persistent layer is object or relational.

Indy

To write socked-based apps

InterBase

Client/server RDBMS, still available from Borland as a commercial tool, but also available as open-source under the name of Firebird

IntraWeb

To create visual web applications (?)

Model Maker

To create UML class diagrams and generate code. Delphi 8 introduces Together, which is also a CASE UML tool and was already available in other Borland products like JBuilder or C++BuilderX.

PAS

Source file in Pascal

RAVE

To generate reports

Unit

Program module. In a Delphi application, every form has a corresponding unit behind it.

VCL

Visual Component Library (VCL)

RTL

Run-time library; Large collection of functions

Q&A

Add to read the selected item in a ComboBox?

ShowMessage(ComboBox1.Text);

Child forms: MDI or frame or pagecontrol?

If you need to show different sets of controls, you can do this either through MDI child windows (the main form being the MDI parent), stand-alone frames, or frames displayed in a pagecontrol (tab widget).

Unlike regular forms, MDI child windows can not be shown modal (so you can’t just use a simple try/finally to remove the object from memory with Free(), and you’ll have to have the MDI child window call some routine in its parent window to have it be removed from RAM), and they flicker when displayed. A frame doesn’t show flickers when it is displayed. Both MDI child windows and frames require calling their parent to be removed from RAM.

How to add a routine to the list in the class?

After writing the routine, you can have it added to the form’s class by using the keyboard combination CTRL-SHIFT-C

Get a list of methods, properties, and events provided by an object?

Either use Delphi’s Runtime Type Information (RTTI), or (no: Doesn’t display anything) GExpert‘s Class Browser.

How to install GExperts?

How to upgrade CnWizards?

Close the IDE and run the installer

TControl(Sender) vs. Sender as TControl?

(From embarcadero.public.delphi.language.delphi.general):

  • Sender as TControl : Throws an exception if Sender is not a TControl
  • TControl(Sender): Silently ignores it if sender is not a TControl, which will have unexpected results.. :). Faster than ‘as’ if you know that sender definitely is a TControl.

How can a runtime frame notify its parent form?

In the frame:

type
  TFrame3 = class(TFrame)
  private
    FOnDone: TNotifyEvent;
  public
    property OnDone: TNotifyEvent read FOnDone write FOnDone;
  end;
 
procedure TFrame3.Button2Click(Sender: TObject);
begin
  if Assigned(FOnDone) then begin
    FOnDone(Self);
  end;
end;

In the form:

interface
 
const
  APPWM_FREE_FRAME = WM_APP + 100;
 
type
  TForm1 = class(TForm)
  private
    procedure FrameIsDone(Sender: TObject);
    procedure AppWmFreeFrame(var Message: TMessage); message APPWM_FREE_FRAME;
  end;
 
procedure TForm1.AppWmFreeFrame(var Message: TMessage);
begin
    TFrame(Message.LParam).Free;
end;
 
procedure TForm1.FrameIsDone(Sender: TObject);
begin
  if Sender is TFrame3 then begin
    PostMessage(Handle, APPWM_FREE_FRAME, 0, Integer(Sender));
  end;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  Frame3 : TFrame3;
begin
  Frame3 := TFrame3.Create(nil);
  Frame3.Align := alClient;
  Frame3.Parent := Self;
  Frame3.OnDone := FrameIsDone;
  Frame3.Visible := True;
end;

ie. calling TFrame1.Done changes the frame’s OnDone property, which triggers the frame’s FOnDone custom event which is linked to the form’s FrameIsDone procedure, which calls AppWmFreeFrame to call PostMessage and actually unload the frame from memory.

How to close a dynamically-created form?

In the calling form:

if Form2 = nil then begin
    Form2 := TForm2.Create(nil);
    Form2.Show;
end;

In the dynamically-created form:

procedure TForm4.Button2Click(Sender: TObject);
begin
  Close;
end;
procedure TForm4.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  Form2 := nil;
end;

How to check that a datamodule is loaded?

  1. Project > Options, and make sure the datamodule is loaded first before any form is loaded
  2. In a form, use the following code to double-check:
    if Assigned(DataModule3) then begin
        ShowMessage(‘assigned’);
    end else begin
        ShowMessage(‘not assigned’);
    end;

How to use ExeName in a datamodule?

If  you need to get the application’s ExeName in a datamodule, either add “Forms” to the Use clause, or change Application.ExeName to ParamStr(0).

Can the IDE show the matching end for a given begin?

  • Castalia
  • Gexperts has editor experts to do this..you can also use the Delforex code formatter to lin up the pairs. Delforex is now part of Gexperts. GExperts allows you to locate a matching delimiter (eg find an “end” from a “begin”), but it doesn’t highlight them automatically like Castalia, for instance.
  • CnPack uses color highlighting to do just that. Works pretty well. I don’t know if CnPack is available for RDS2007 yet though…

How to support Far-East languages in Delphi 7

Why use Delphi over VB?

Why use Delphi over Borland C++?

The reason I mention Borland C++ over MS VC++ is that I read that the former has a tool that lets you build GUI screens graphically, while the latter still requires you to write the whole thing in code, so cannot be reasonably compared to Delphi or VB.

Personally, I find C/C++ a pain to use, because the language itself requires your paying attention to details that are just a waste of time most of the time when developing client-side applications, and keep you from concentrating on the problem the application is trying to solve. Considering you can build tight, dependency-free code with Delphi, what’s the point of wasting time with a lower-level language that was originally just meant for system development back in 1970?

Why upgrade from D7?

IDE 

  • New Memory Manager.
  • Improved Speed for Several Features.
  • Change Parameters Refactoring.
  • Message view

Form Designer

  • Design Guidelines.
  • Form Positioner

Code Editor:

  • New code templates.
  • Surround templates.
  • Live templates editing.
  • Block completion.
  • Method navigation.
  • Improved Code Editor gutter.
  • Diff highlighting.
  • Close all other pages.
  • Refactoring

Debugger

  • Remote debugging.
  • Symbol table management.
  • Expandable watches.
  • CPU view.
  • Sort by load order.
  • Close implicitly opened files.   

dbExpress

  • dbExpress Unicode support.
  • ConnectionString property.
  • Customizable decimal separator.
  • TSQLQuery support.

VCL

  • New components: TTrayIcon, TGridPanel, TFlowPanel
  • New classes: TCustomTransparentControl, TMargins, TPadding

Delphi Language Enhancements:

  • Operator overloading
  • Non-virtual method declaration
  • Regular instance methods
  • Constructors with non-empty parameter lists
  • Static methods and properties
  • FastMM built in

More information on changes since Delphi 7

Why install IDE add-on’s GExperts and cnWizard?

cnWizards shows a list of bookmarks (CTRL-SHIFT-b) and a list of routines (CTRL-d).

GExperts offers a Class Browser to see the list of methods, properties, and events provided by an object.

Why use Delphi vs. alternatives to write .Net apps?

Since the main selling point was the productivity of VB but the speed/compactness of VC++, I don’t see the added-value of using Delphi 2005 over VB.Net, unless you’re more familiar with Delphi and would rather use the same language to work with .Net.

After moving routines into Unit2, the project stops compiling

Make sure Unit2 is referenced in Unit1’s Implementation through “Uses Unit2”, and that all exported routines in Unit2 are declared in Unit2’s Interface section.

How can I change the application’s icon?

Project Options

How to change the default application icon?

Why does my local array start at 0 instead of 1?

An array created in a routine (procedure or function), even if its size is statically defined, is considered an “open array”, and thus, starts at 0:

procedure Check(var ReturnArray: Array of String);
var
  Index : Integer;
begin
  // Says 1!
  ShowMessage(IntToStr(High(ReturnArray)));
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  ReturnArray : Array[1..2] of String;
begin
  //Says 2, as expected
  ShowMessage(IntToStr(High(ReturnArray)));
 
  Check(ReturnArray);
end;

If you want the array to start at something else than 0, define the array as a new type:

type
  TMyArray = Array[1..2] of String;
  TForm1 = class(TForm)
  …
procedure Check(var ReturnArray: TMyArray);
var
  Index : Integer;
begin
  ShowMessage(IntToStr(High(ReturnArray)));
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  ReturnArray : TMyArray;
begin
  ShowMessage(IntToStr(High(ReturnArray)));
 
  Check(ReturnArray);
end;

How to have a listbox scroll down programmatically?

  • PostMessage(Listbox1.Handle, wm_vscroll, SB_LINEDOWN, 0); //Works in loop
  • ListBox1.ItemIndex := ListBox1.Items.Add(‘bla’); //Flickers
  • ListBox1.ItemIndex := ListBox1.Items.Count – 1; //Flickers

How do I use regexes in Delphi?

  • TPerlRegEx (free wrapper around PCRE, with additional support for replace and split actions; “You can choose to link the OBJ files directly into your application, or to use the DLL”; Under active development; Made by author of www.regular-expressions.info)
  • PCRE Wrapper for Delphi 7 (requires a DLL; Under active development)
  • Delphi Regex Library (free for personal use; Last updated 2001)
  • DIPcre and DIRegEx (new version of DIPcre? Euro 20,00; Euro 60,00 with sources)
  • TRegExpr (Freeware Delphi Regular Expressions Library; Comes with Unit source, hence no need for DLL; Development stopped in 2004)
  • Turbo SysTools (Deadware; The StRegEx unit implements the TStStreamRegEx class and TStRegEx component)

TPerlRegex

To install this RegEx engine for Delphi, open, compile and install PerlRegExD7.dpk, which creates PerlRegExD7.bpl, add its directory to the Library path, and add a TPerlRegEx control to the project’s form.

Here’s how to extract a single bit in a text:

PerlRegEx1.RegEx := ‘<title>(.+?)</title>’;
PerlRegEx1.Options := [preCaseLess];
PerlRegEx1.Subject := ‘test <title>bla</title> test’;
If PerlRegEx1.Match then begin
    ShowMessage(PerlRegEx1.SubExpressions[1])
end else begin
    ShowMessage(‘Not found’)
end;

Next, here’s how to look for a pattern, and extract bits if found:

var
    RegEx : TPerlRegEx;
    Stuff : TStringList;
begin
    RegEx := TPerlRegEx.Create(nil);
    Stuff := TStringList.Create;
    Try
        RegEx.RegEx := ‘my pattern’;
        RegEx.Options := [preCaseLess];
        RegEx.Subject := ‘this is the text to search for my pattern’;
        
        If RegEx.Match then begin
            repeat
                for i := 1 to regex.SubExpressionCount do begin
                    Stuff.Add(regex.SubExpressions[i]);
                    Application.ProcessMessages;
                end;
            until not RegEx.MatchAgain;
 
            For I := 0 to Stuff.Count – 1 do begin
                Memo1.Lines.Add(Stuff[I]);
            end;
 
        end else begin
            ShowMessage(‘Not found’);
        end;
 
    Finally
        RegEx.Free;
        Stuff.Free;
    End;
End;

Here’s how to replace a pattern with something else:

RegEx := TPerlRegEx.Create(nil);
try
    RegEx.Subject := LoadFile(‘myfile.txt’);
    RegEx.RegEx := ‘HERE’;
    RegEx.Replacement := ‘THERE’;
    If RegEx.Match then begin
        RegEx.Replace;
        ShowMessage(RegEx.Subject);
    end;
finally
    RegEx.Free;
end;

TRegExpr

Although TRegExp is much slower than TPerlRegEx on more complex operations, it’s OK for light searches. Here’s how to extract tokens from a text file using TRegExpr:

MyStuff := ‘<body>My stuff</body>’;
 
with TRegExpr.Create do
    try
        //Make it case-insensitive
        ModifierI := True;
        
        Expression := ‘<body.*>(.*?)</body>’;
        if Exec (MyStuff) then
            ShowMessage(Match[1]);
 
    finally
        Free;
end;

Here’s how to extract several tokens, and put them in an array:

var
    Tokens : TStringList;
    MyRegex : TRegExpr;
 
begin
    MyRegex := TRegExpr.Create;
    Tokens := TStringList.Create;
    try
        MyRegex.ModifierI := True;
        MyRegex.Expression := ‘some stuf (\d+) some other stuff’;
        if MyRegex.Exec (Response) then begin
            REPEAT
                Tokens.Add (MyRegex.Match[1])
            UNTIL not MyRegex.ExecNext;
 
            Memo1.Clear;
            for I := 0 to Tokens.Count-1 do begin
                Memo1.Lines.Add(Tokens[I]);
            end;
 
        end else begin
            Memo1.Text := ‘Pattern Not Found’;
        end;
    finally
        MyRegex.Free;
        Tokens.Free;
    end;

And here’s how to look for patterns, and replace them with something else:

ShowMessage(ReplaceRegExpr (‘World’,’Hello, World!’, ‘Earth’));

You can also use references:

MyStuff := ‘The number 123 here’;
MyStuff := ReplaceRegExpr (‘The number (\d+) here’,MyStuff, ‘Rewritten as $1’, True);
ShowMessage(MyStuff);

Can I arrange the IDE to get a similar layout to VB’s IDE?

You can combine the Object Inspector and Object TreeView windows through drag and drop,and dock them to the text editor with further drag and drop. Then, to tell Delphi to keep this layout, hit View > Desktops > Save Desktop, and give a name to this new layout.

Can I use Delphi without VCL?

You can write programs using just the Object Pascal, a.k.a. Delphi, language and make direct calls to the Windows API so as to builder smaller programs. Read Programming In A Subset Of Delphi, and DelphiZeus – Developing Delphi programs in Windows API without the Forms unit for more info.

How to get an MDI child form to use the whole client area?

procedure TForm1.RzGroup1Items0Click(Sender: TObject);
var
  Form2 : TForm2;
begin
  Form2 := TForm2.Create(Application);
  //BAD Form2.Align := alClient;
  Form2.Align :=
end;

How to close a child MDI form?

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

GPF when showing a second form

First, it looks like it’s not enough for the second form to be part of the project: It must also be listed in the Uses section of the first form (ie. Uses Unit2), along with the var section of its interface (var Form2: TForm2;), before being called with this kind of code:

begin
  Form2 := TForm2.Create(Application);
  ShowMessage(Form2.Name);
  Form2.Show;
end;

I messed up Delphi with an update, and get errors at start-up!

I had an issue with the Rave part after running the 7.1 update. Here’s how to restore Delphi:

  1. Exit the IDE
  2. Back up your source files
  3. Run D7RegClean.exe from your delphi BIN directory
  4. Uninstall delphi
  5. Reboot
  6. Reinstall.

I don’t know if it hurts, but I also deleted Rave50CLXBE70.bpl and Rave50VCLBE70.bpl from \SYSTEM32.

Why use a package vs. a DLL?

(From “Delphi in a nutshell”) A package has the extension .bpl (“Borland Package Library”), and avoid the problem of DLLs, namely, managing memory and class identities.

In the Project menu, what’s the diff between Compile and Build?

Compiled = turn each PAS file into object code (DCU?), while Build = link all the compiled units into an EXE?

I can’t compile my first program!

You must first save the .PAS file and the .DPR project file for the Project | Build Project to generate the EXE.

Can I compile DLLs and OCXs inside a big EXE?

From Greg Lorriman in comp.lang.pascal.delphi.misc (1999/10/03)

“The ocx’s are NOT compiled into a delphi app. In this regard delphi has the same relationship to ocx’s as VB. But a delphi app is much less likely to use ocx’s than a VB app. I’ve never used one (except experimentally). […]
 
So long as the components are native to Delphi then they can be compiled into the executable. By default the rest of the support code (which comes as runtime dll’s in VB) is also compiled into the executable. This results in a single exe and no need for runtime dll’s. Component publishers often offer delphi native versions of their ocx components.  The delphi executable is relatively large but no way near as big as the VB exe/dll combination.
 
A significant advantage is that the versioning problems that affect ocx’s don’t exist in delphi and you don’t force the end user to download any large runtime dll’s. (ocx’s, incidentally, tend to be much larger than their delphi cousins).
 
However, delphi also offers the option of the VB approach (small exe and runtime dll’s) and calls the dll’s “packages”.  The delphi method of implementing the dll approach is slightly more sophistocated than VB. Both approaches have their pros and cons.
 
Neither language can do much about ocx’s, though delphi does at least offer an escape route.”

How to create smaller EXEs?

  • Don’t use any VCL package, eg. if the application uses no forms or you’re willing to make calls to the Win32 API yourself, you can remove the reference to the Forms unit, and save a lot in terms of EXE size
  • Build the EXE with packages, ie. the VCL stuff is kept in external .BPL files that you’ll need to provide with the EXE, but will not have to ship again the next time the EXE is updated
  • Shrink the EXE using binaries compressors like UPX, Shrinker, etc.
  • “The optimizer normally deletes all functions which are not needed. So it doesn’t matter how many units are in the uses clause. Only the needed functions will be linked into the EXE > Actually, that’s not quite the case – if there’s an initialization clause or a  Register procedure, quite often the whole thing will get linked in – the  “class of” types and the like ensure that if the unit is used, it will have all the binary available just in case there’s a TStream.ReadComponent(nil) and an object of that class happens to be in the stream file. Works in many cases for one’s own units, though. There’s a similar logic to why the linker can’t get rid of virtual/dynamic methods. > You can pull the same sort of trick with Delphi, if you care to. The “build with runtime packages” option lets you have a much smaller .exe, with the base Delphi class library residing within a bunch of files beginning with “vcl” in  your C:\Windows\System directory. Since Delphi’s not quite as common as some  programming languages, you’re more likely to need to distribute these, but you  can issue a much smaller update. Our clients seem to be willing to take the standard everything-compiled-in approach simply for ease of deployment.”

Can’t set string in routine?

Why does this display an empty dialog?

procedure Weird(Stuff : String);
begin
  Stuff := ‘here’;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  MyStuff : String;
 
begin
    Weird(MyStuff);
    ShowMessage(MyStuff);

Why can’t I use String in MessageBox?

var
    MyTitle : String;
begin
      MessageBox(‘text’, MyTitle, [smbOK]);

Is it possible to open more than one project at the same time?

Do I really need to call Free() after each Create(), or does Delphi frees memory when the program ends?

Yes, because unlike internal data types like String or Integer, objects must be created manually through Create() and freed with… Free().

As for the consequences of forgetting to call Free:

CodeGuard cannot report anything that takes place in Windows *after* your application terminates. It correctly reports that, at the time of termination, your application has failed to explicitly release some memory. Windows, barring some other error, tracks all memory allocations for a process and, upon termination, will free up that memory anyway. So that, in itself, is not the issue.
 
The issues are:
1) as long as your application *continues to run* it will be holding memory unnecessarily that cannot be used by other processes. If it is a repeated leak then eventually the system *will* run out of memory.
 
2) It isn’t just a matter of memory but also other O/S resources. For example if the object you forget to free is holding open file handles or a COM or TCP port, or graphic resources, etc, then again that is impairing the operation of the system and, in some of these cases, it may be that they *won’t* be fully cleaned up by Windows after the application terminates.
 
3) Simply bad programming practice to not cleanup properly.

Besides always adding a Try/Finally to .Free() any object, it’s a good habit to check a projet with the FullDebugMode option of FastMM, especially during the initial construction phase of the project.

“[Fatal Error] File not found bla.dcu” after installing a new package

After installing a new design-time package (*.DPK) through File > Open > Install, you also need to add the path to its *.DCU files through Tools > Environment Options > Library, in the Library Path.

How to avoid interface freezing during long loops?

Application.ProcessMessage

Get an objet’s methods/properties/events?

Some utilities (such as this one) use RTTI to read this from an object which requires upgrading to Delphi 2010 for full information (more basic information available through RTTI on previous versions of Delphi).

Get column datatype from dataset?

Here’s how to get the datatype expected from a column in a dataset (untested):

uses
  TypInfo;
var
  aDataType: TDataType;
aDataType := MyQuery.FieldByName(‘FieldName’).DataType;
ShowMessage(GetEnumName(TypeInfo(aDataType), Ord(aDataType));

Alternative:

//DataType is not a string, and therefore can’t be typecast to a string -> Ord()
ShowMessage(IntToStr(Ord(ASQLite3Query1.Fields[myCol].DataType)));

Delphi Peeves

IDE

  • Can’t set bookmarks (eg. F2 in UltraEdit)? The best I found, is CnWizard’s use of “margin number”
  • Moving the caret up/down doesn’t move it to the end of the line on which it ends (must hit End)
  • No foldable blocks, or at least vertical hints to show indentation
  • Can’t save a whole project under a different name, in a different folder? (File > Save As = individual .PAS file; File > Save Project As = only saves project files like .DPR, .DOF, etc., but leaves all other files in original folder, updating paths)
  • Can’t comment block with {} if it already contains a commented block -> must use {$IfDef Bla}…{$EndIf}

Language

  • The structure to handle exceptions could be improved. Even in D2006, it’s either try/except or try/finally, but some cases need a more fine-tuned structure:

      try
        IdTCPClient1.Connect;
        ShowMessage(‘ok’);
        IdTCPClient1.Disconnect;
      except
        ShowMessage(‘failed connecting’);
      finally //Stuff to run whatever the outcome
        ShowMessage(‘this message displayed every time’);
      end;

How to display PNG on BitButn?

D2009 supports this, but not older versions. Take a look at these:

Places to find icons:

Resources

Learning Pascal

Learning Delphi

Sites

Books

Learning Delphi.Net

Tools

News

Fibonacci Entanglement

The Fibonacci Sequence is the series of numbers:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 …

https://www.mathsisfun.com/numbers/fibonacci-sequence.html

In this blog I want to demonstrate code of 30 programming languages to compute the fibonacci sequence, lets start with Pascal and maXbox:

f:=0; g:=1;
for it:= 1 to 30 do begin
  f:= f+g
  g:= f-g
end;
writeln(itoa(f));
>>> 832040

Second language is SuperCollider (Smalltalk):

var f1, b1;
f1 = 0;
b1 = 1;
30.do({ arg i;
  f1 = f1 + b1;
  b1 = f1 - b1;
("" ++ (i+1) ++ " f1: " ++ f1).postln;
}));
30: 832040

Third language is Python:

f=0; g=1
for i in range(30):
  f=f+g
  g=f-g
>>> f
832040

print(“”.join(map(lambda x: chr(ord(x)^3),’Hello, world!’)))
>>> Kfool/#tlqog”

shortest cryptography as 3 is key

4. Fibonacci series program in C

#include <stdio.h>

int main()
{
  int n, first = 0, second = 1, next, c;

  printf(“Enter the number of terms\n“);
  scanf(“%d”, &n);

  printf(“First %d terms of Fibonacci series are:\n“, n);

  for (c = 0; c < n; c++)
  {
    if (c <= 1)
      next = c;
    else
    {
      next = first + second;
      first = second;
      second = next;
    }
    printf(“%d\n“, next);
  }

  return 0;
}

5. Java:

  1. class FibonacciExample1{  
  2. public static void main(String args[])  
  3. {    
  4.  int n1=0,n2=1,n3,i,count=31;    
  5.  System.out.print(n1+” “+n2);//printing 0 and 1    
  6.  for(i=2;i<count;++i)//loop starts from 2 because 0 and 1 are already printed    
  7.  {    
  8.   n3=n1+n2;    
  9.   System.out.print(” “+n3);    
  10.   n1=n2;    
  11.   n2=n3;    
  12.  }    
  13. }}  

6. C++

  1. #include <iostream>  
  2. using namespace std;  
  3. int main() {  
  4.   int n1=0,n2=1,n3,i,number;    
  5.  cout<<"Enter the number of elements: ";    
  6.  cin>>number;    
  7.  cout<<n1<<" "<<n2<<" "; //printing 0 and 1    
  8.  for(i=2;i<number;++i) //loop starts from 2, 0 and 1 printed    
  9.  {    
  10.    n3=n1+n2;    
  11.    cout<<n3<<" ";    
  12.    n1=n2;    
  13.    n2=n3;    
  14.  }    
  15.    return 0;  
  16.    }  

7. C#

  1. using System;  
  2.   public class FibonacciExample  
  3.    {  
  4.      public static void Main(string[] args)  
  5.       {  
  6.          int n1=0,n2=1,n3,i,number;    
  7.          Console.Write("Enter the number of elements: ");    
  8.          number = int.Parse(Console.ReadLine());  
  9.          Console.Write(n1+" "+n2+" "); //printing 0 and 1    
  10.          for(i=2;i<number;++i)   
  11.          {    
  12.           n3=n1+n2;    
  13.           Console.Write(n3+" ");    
  14.           n1=n2;    
  15.           n2=n3;    
  16.          }    
  17.       }  
  18.    }  

8. PHP

  1. <?php  
  2. $num = 0;  
  3. $n1 = 0;  
  4. $n2 = 1;  
  5. echo "<h3>Fibonacci series for first 30 numbers: </h3>";  
  6. echo "\n";  
  7. echo $n1.' '.$n2.' ';  
  8. while ($num < 28 )  
  9. {  
  10.     $n3 = $n2 + $n1;  
  11.     echo $n3.' ';  
  12.     $n1 = $n2;  
  13.     $n2 = $n3;  
  14.     $num = $num + 1;  
  15. ?>  

9. JavaScript

function fibonacci(num){
var a = 1, b = 0, temp;

while (num >= 0){
temp = a;
a = a + b;
b = temp;
num--;
}

return b;
}

10. Delphi

function Fibonacci(aNumber: Integer): Integer;
begin
  if aNumber < 0 then
    raise Exception.Create('Fibonacci sequence is not defined for negative integers.');
  case aNumber of
  0: Result:= 0;
  1: Result:= 1;
  else
    Result:= Fibonacci(aNumber - 1) + Fibonacci(aNumber - 2);
  end;
end;

11. Pascal

function fibonacci4(numb: byte): integer;
var f, g, i: integer;
begin
f:= 0; g:= 1;
for i:= 1 to 30 do begin
f:= f+g
g:= f-g
end;
result:= f
end;

12. Pearl

#!/bin/perl -wl
#
# Prints the sequence of Fibonacci numbers with arbitrary
# precision. If an argument N is given, the program stops
# after generating Fibonacci(N).

use strict;
use bigint;

my $n = @ARGV ? shift : 1e9999;

              exit if $n < 0;
print "0: 0"; exit if $n < 1;
print "1: 1"; exit if $n < 2;

my ($a, $b) = (0, 1);
for my $k (2 .. $n) {
    ($a, $b) = ($b, $a+$b);
    print "$k: $b";
}

13. Ruby

http://www.codecodex.com/wiki/Calculate_the_Fibonacci_sequence

  1. #!/usr/bin/env ruby  
  2. a, b = 0, 1  
  3. puts “0: #{a}”  
  4. 100.times do |n|  
  5.      puts “#{n+1}: #{b}”  
  6.      a, b = b, a+b  
  7. end  

Data Science Stuff

BASTA EKON 2020 Demo for Neural Net Visuals, locs=266

from converter import app, request
import unittest
import os

os.environ[“PATH”] += os.pathsep + ‘C:/Program Files/Pandoc/’

BASEPA = ‘C:/maXbox/maxbox3/maxbox3/maXbox3/crypt/viper2/’

class TestStrings(unittest.TestCase):
def test_upper(self):
self.assertEqual(“spam”.upper(), “SPAM”)
def test_lower(self):
self.assertEqual(“Spam”.lower(), “spam”)

class ConvertTestCase(unittest.TestCase):
def setUp(self) -> None:
app.testing = True

def test_two_paragaraps(self):
    markdown = "This is the text of paragraph 1.\n\nThis is the second text."
    with app.test_client() as test_client:
        response = test_client.post('/', data=markdown)
        tree = response.get_json()
    self.assertEqual({"type": "block-blocks", "blocks": [{
        "type": "block-paragraph",
        "spans": [{"type": "span-regular",
                   "text": "This is the text of paragraph 1."}]
    }, {
        "type": "block-paragraph",
        "spans": [{"type": "span-regular",
                   "text": "This is the second text."}]
    }]}, tree)

class RequestContextTestCase(unittest.TestCase):
def setUp(self) -> None:
app.testing = True

def test_request_context_multiline_text(self):
    markdown = "This is the text of paragraph 1.\n\nThis is the second text."
    with app.test_request_context('/', method='POST', data=markdown):
        self.assertEqual(request.get_data(as_text=True), markdown)

import random
import math
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVR
from sklearn.metrics import mean_squared_error

Next, we create sample data.

Datarange = 100

random.seed(12345)
def getData(N):
x,y = [],[]
for i in range(N):
a = i/8+random.uniform(-1,1)
yy = math.sin(a)+3+random.uniform(-1,1)
x.append([a])
y.append([yy])
return np.array(x), np.array(y)

x,y = getData(Datarange)

model = SVR(gamma=’auto’) #=’scale’
print(model)

model.fit(x,y)
pred_y = model.predict(x)

for yo, yp in zip(y[1:15,:], pred_y[1:15]):
print(yo,yp)

“””
[2.12998819] 2.3688522493273485
[2.91907141] 3.285632204333334
[3.02825117] 2.953252316970487
[3.21241735] 3.3448365096752717
[2.84114287] 2.7413569211507602
[2.09354503] 2.629728633229279
[2.71700547] 3.092804036168382
[2.97862119] 3.2818706188759346
[3.40296856] 3.0690924469559113
[3.15686687] 3.8962639841272315
[3.95510045] 2.963577687955483
[4.06240409] 2.8227461040611517
[3.52296771] 3.623387735802008
[4.41282252] 3.8982877638029247
“””

x_ax=range(Datarange)
plt.scatter(x_ax, y, s=5, color=”blue”, label=”original”)
plt.plot(x_ax, pred_y, lw=1.5, color=”red”, label=”predicted”)
plt.title(‘high variance – be overfitted’)
plt.legend()
plt.show()

score=model.score(x,y)
print(score)

0.6066306757957185

mse =mean_squared_error(y, pred_y)
print(“Mean Squared Error:”,mse)

Mean Squared Error: 0.30499845231798917

rmse = math.sqrt(mse)
print(“Root Mean Squared Error:”, rmse)

Root Mean Squared Error: 0.5522666496521306

How to Fit Regression Data with CNN Model in Python

https://www.datatechnotes.com/2019/12/how-to-fit-regression-data-with-cnn.html

from sklearn.datasets import load_boston
from keras.models import Sequential
from keras.layers import Dense, Conv1D, Flatten
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt

boston = load_boston()
x, y = boston.data, boston.target

print(x.shape)

(506, 13)

An x data has two dimensions that are the number of rows and columns.

Here, we need to add the third dimension that will be the number of the single input row.

x = x.reshape(x.shape[0], x.shape[1], 1)
print(‘Shape with single input row ‘,x.shape)

xtrain, xtest, ytrain, ytest=train_test_split(x, y, test_size=0.15)

model = Sequential()
model.add(Conv1D(32, 2, activation=”relu”, input_shape=(13, 1)))
model.add(Flatten())
model.add(Dense(64, activation=”relu”))
model.add(Dense(1))
model.compile(loss=”mse”, optimizer=”adam”)

model.summary()

Next, we’ll fit the model with train data.

model.fit(xtrain, ytrain, batch_size=12,epochs=200, verbose=0)

ypredtrain = model.predict(xtrain)
print(“MSE Train: %.4f” % mean_squared_error(ytrain, ypredtrain))

Now we can predict the test data with the trained model.

ypred = model.predict(xtest)

21.21026409947595

print(“MSE Predicts: %.4f” % mean_squared_error(ytest, ypred))
print(‘MSE Evaluate: ‘,model.evaluate(xtest, ytest))

MSE: 19.8953

x_ax = range(len(ypred))
plt.scatter(x_ax, ytest, s=5, color=”blue”, label=”original”)
plt.plot(x_ax, ypred, lw=0.8, color=”red”, label=”predicted”)
plt.legend()
plt.show()

“””
https://medium.com/code-heroku/introduction-to-exploratory-data-analysis-eda-c0257f888676

Here is a quick overview of the things that you are going to learn in this article:

Descriptive Statistics
Grouping of Data
Handling missing values in dataset
ANOVA: Analysis of variance
Correlation

“””

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy import stats
df = pd.read_csv(BASEPA+’data/automobile2.csv’) #read data from CSV file

print(df.head())
print(df.describe())

print(df[‘num-of-doors’].value_counts())

sns.boxplot(x=’num-of-cylinders’,y=’price’,data=df)
plt.show()

plt.scatter(df[‘engine-size’],df[‘price’])
plt.xlabel(‘Engine Size’)
plt.ylabel(‘Price’)
plt.show()

“””
count,bin_edges = np.histogram(df[‘peak-rpm’])
df[‘peak-rpm’].plot(kind=’hist’,xticks=bin_edges)
plt.xlabel(‘Value of peak rpm’)
plt.ylabel(‘Number of cars’)
plt.grid()
plt.show()
“””

df_temp = df[[‘num-of-doors’,’body-style’,’price’]]
df_group = df_temp.groupby([‘num-of-doors’,’body-style’],as_index=False).mean()
print(df_group)

show missing values

sns.heatmap(df.isnull())

plt.show()

ANOVA is a statistical method which is used for figuring out the relation between different groups of categorical data.

F-test score: It calculates the variation between sample group means divided by variation within sample group.

Correlation is a statistical metric for measuring to what extent different variables are interdependent.

temp_df = df[[‘make’,’price’]].groupby([‘make’])
print(stats.f_oneway(temp_df.get_group(‘audi’)[‘price’],temp_df.get_group(‘volvo’)[‘price’]))

temp_df.plot()

plt.show()

print(stats.f_oneway(temp_df.get_group(‘jaguar’)[‘price’],temp_df.get_group(‘honda’)[‘price’]))

“””
Notice that in this case, we got a very high F-Test score(around 401) with a p value around 1.05 * 10^-11
because, the variance between the average price of “jaguar” and “honda” is huge.
“””

In demography, demographic transition is a phenomenon and theory which refers to the historical shift from high birth rates and high infant death rates in societies with minimal technology, education (especially of women) and economic development, to low birth rates and low death rates in societies with advanced technology, education and economic development, as well as the stages between these two scenarios.

“””
plt.bar(df[‘make’],df[‘price’])
plt.xlabel(‘Maker’)
plt.ylabel(‘Price’)
plt.show()
“””
“””
correlation_matrix = df.corr()
sns.heatmap(correlation_matrix, annot=True)
plt.show()
“””

sns.regplot(x=’engine-size’,y=’price’,data=df)
plt.show()
sns.regplot(x=’highway-mpg’,y=’price’,data=df)
plt.show()

if name__ == ‘__main‘:
unittest.main()

ref for remote testing: https://www.javatpoint.com/selenium-python

Breitsch Buch

Der Breitsch – ein Fels in der Brandung.

Warum wieder ein Buch, dass notabene 2030 erscheint!?

Der Breitschtraeff im Juni 2020


Der Breitsch-Traeff wird im Jahre 2030 sage und schreibe 50 Jahre alt.

Die Zeit beunruhigender Entwicklungen hat viele Facetten – die offenkundigste ist das Erfordernis einer realistischen Antwort auf die menschengemachte Klima-Krise unseres Planeten; eine andere, die in fast allen Lebensbereichen überfordernde Komplexität auszuhalten und die ersehnte Klarheit in unseren Leben zu finden, ohne auf Leugnen, empörungsbereite Vereinfachung und medial beschleunigte Erregungsmuster zurückzufallen.


Das Buch zeigt 50 zeitlose Geschichten und Portraits mit einer Klarheit und Weitsicht als Trost in einer Welt die brennt.

Erscheinung: 2030, Preis 50 SFr., Umfang 100 Seiten

Jubiläumsmonat November 2020

Na ja die Vorteile fürs Quartierfest sind mannigfaltig:
In der Jubiläumszeit ist auch Wahlkampf angesagt, so dass ein Quartier
von der Meinungsbildung profitiert. Dann gibts natürlich Essen und Trinken; sind
immer noch die unmittelbarsten Erfahrungen, die einen Menschen
zufriedenstellen – oder eben auch nicht.
Eine Jubiblatt dient dem Quartier als historischen Beweis der
Beständidkeit – eine Illustrierte mit Anekdoten, Fakten und Bildern in
der Ausstellung.

Die Veranstaltung ist daher auch ein wichtiger Baustein in der
Öffentlichkeitsarbeit, das Angebot im Träff zu propagieren.
Zudem ist das Jubiläum der geeignete Zeitpunkt, Potenziale des
Breitschträffs für die Zukunft ins Gespräch zu bringen; und im Quartier
mit Ideen zu punkten.

Planungsübersicht Samstag 7.11.20  ab 17.30h

Vernissage der Fotoausstellung, Abend mit geladenen Gästen (Politik, vbg, Ehemalige etc.) und Anekdoten.

Sonntag  8.11.20  Sonntagsbrunch: dies müssen wir mit der Gruppe Kutüsch absprechen, da sie jeden Sonntags ab 12.30 h im BT sind. Donnerstag 12.11.20 ab 19h: Reserviert, Thema noch offen. Samstag 14.11.20 ab 19h Disco Breitsch 40. Montag 16.11.20 ab 19h: Reserviert, Thema noch offen. Samstag 21.11.20 ab 19h Schlussabend Breitsch 40 mit Abendessen und Musik (Filmtage nur am 19. und 20. Nov. 2020).

TEE Paris – Ruhr

From right to left and front to rear:
H22057-1 184 003-2 (four system loc available individually as H2883 – the very same prototype was also produced by Minitrix decades ago as nos. 2938/12938), H22057-2 generator/open 1st A4Dtux, H22057-3, open 1st A8tu, H22058-1 dining car Vru,
H22058-2 compartment 1st A8u (red interior), H22058-4 half bar/open 1st A3rtu, H22058-3 compartment 1st A8u (yellow interior)

<style>
svg     { background-color: black; }
polygon { fill: none; }
</style>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-150 -150 300 300">
     </svg>
     <script>
      const TRIANGLES = 90 ;
      let   rot       = 0 ;
      
      function rotate()
      {
         let polygons = document.querySelectorAll( "polygon" ) ;
         let angle    = 0 ;
      
         for( let i = 0; i < polygons.length; i++ )
         {
            triangle = polygons[i] ;
            triangle.setAttribute( "transform", `rotate(${rot-2*i*360/TRIANGLES},${83.09*Math.sin(angle)},${83.09*Math.cos(angle)})` ) ;
            angle += 2 * Math.PI / TRIANGLES ;
         }
      
         rot   += 1.5 ;
      }
      
      function init()
      {
         let svg   = document.querySelector( "svg" ) ;
         let angle = 0 ;
      
         for( let i = 0; i < TRIANGLES; i++ )
         {
            let triangle = document.createElementNS( "http://www.w3.org/2000/svg", "polygon" ) ;
            triangle.setAttribute( "points", `${72.11102*Math.sin(angle-0.59)},${72.11102*Math.cos(angle-0.59)} ${72.11102*Math.sin(angle+0.59)},${72.11102*Math.cos(angle+0.59)} ${129.28*Math.sin(angle)},${129.29*Math.cos(angle)}` ) ;
            triangle.setAttribute( "transform", `rotate(${-2*i*360/TRIANGLES},${83.09*Math.sin(angle)},${83.09*Math.cos(angle)})` ) ;
            triangle.setAttribute( "stroke", `hsl(${i*6},100%,50%)` ) ;
            svg.appendChild( triangle ) ;
            angle += 2 * Math.PI / TRIANGLES ;
         }
      }
      
      init() ;
      setInterval( rotate, 50 ) ;
     </script>
     <h3>JavaScript maXbox4</h3>
Design a site like this with WordPress.com
Get started