Faire une horloge analogique :
Le lien vers un exemple de la forge :
HorlogeUne image :
En cliquant droit on fait apparaître un menu contextuel qui permet de sélectionner des images d'horloges différentes,
d'afficher la date, le logo ou les deux et de sortir du programme.
Le clique gauche est conservé pour effectuer les déplacements de l'horloge.
Logique de construction de l'horloge :
Une horloge tourne dans le sens inverse du cercle trigonométrique.
L'origine de l'horloge est à 12 heures.
l'origine du cercle trigonométrique est à 3 heures.
la translation entre les deux est donc de - 90 degrés.
Une heure = 60 minutes = 3 600 secondes.
Un tour c'est 360 degrés réalisé soit en 60 secondes soit en 60 minutes.
soit 360 / 60 = 6.
en milliseconde : 60 x 1 000 = 60 000.
soit pour un tour : 360 / 60 000 = 0,006
ou son inverse : 60 000 / 360 = 166,6666666667.
Donc pour représenter l'angle d'avancé sur l'horloge :
Angle en degrés pour les heures = (heures x 60 + minutes) / 2 - 90°.
Angle en degrés pour les minutes = minutes x 360 / 60 - 90°.
Angle en degrés pour les secondes = secondes x 360 / 60 - 90°.
Angle en degrés pour les millisecondes = (secondes x 360 / 60 + millisecondes x 360 / 60 000) - 90°.
Pour placer les objets comme les aiguilles sur l'horloge, les coordonnées sur le cercle sont :
Les angles étant convertis de degrés en radians
X = rayon (aiguilles) x Cos(Angle).
Y = rayon (aiguilles) x Sin(Angle).
Pour chaque type d'aiguille , pour obtenir la longueur voulue, il suffit d'appliquer un coefficient réducteur.
Le Code :
Le code du formulaire principal :
Les déclarations :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| ' Gambas class file
STATIC PUBLIC iDesign AS INTEGER STATIC PUBLIC iDrap AS INTEGER STATIC PUBLIC bTrotteuse AS BOOLEAN STATIC PUBLIC bAuto AS BOOLEAN STATIC PUBLIC sText1 AS STRING STATIC PUBLIC sText2 AS STRING
PRIVATE $hPicture AS Picture PRIVATE $iNbreImage AS INTEGER = 12 '<-------------------------------' nombre d'images enregistrées PRIVATE $iHandLength AS NEW INTEGER[$iNbreImage + 1] PRIVATE $cHandColor AS NEW INTEGER[$iNbreImage + 1] PRIVATE $hConsoleTimer AS Timer PRIVATE $iCount AS INTEGER
'The drawing of the clock(s) is based on procedures provided by Hans Lehmann and Ingo Beckert. 'For the user rights please refer to: [url=http://gambas-buch.de/dw/doku.php?id=impressum]http://gambas-buch.de/dw/doku.php?id=impressum[/url]:start 'Claus Dietrich
|
Dimensions des images :
1
2
3
4
5
6
7
8
9
10
| PRIVATE SUB dimPicture1()
PictureBox1.X = 0 PictureBox1.Y = 0 PictureBox1.W = 199 PictureBox1.H = 199 PictureBox1.Mode = PictureBox.Contain PictureBox1.Tooltip = ("Clique droit pour options")
END
|
Les aiguilles de notre montre :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| PRIVATE SUB paramAiguilles()
DIM i AS INTEGER
'<----------------------------------------------------------------' Base length of the hands FOR i = 0 TO $iNbreImage '<---------------------------------------' voir la déclaration du nombre d'images SELECT CASE i '<----------------------------------------------' à corriger si ajout de design CASE 3 $iHandLength[i] = 70 CASE 8 $iHandLength[i] = 90 CASE ELSE $iHandLength[i] = 75 END SELECT NEXT '<----------------------------------------------------------------' Color of the hands FOR i = 0 TO $iNbreImage SELECT CASE i '<----------------------------------------------' à corriger si ajout de design CASE 0 $cHandColor[i] = Color.DarkGray CASE 1, 2 $cHandColor[i] = Color.white CASE 5 $cHandColor[i] = Color.Yellow CASE 10 $cHandColor[i] = Color.Green CASE ELSE $cHandColor[i] = Color.black END SELECT NEXT
END
|
Actions menu contextuel :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| PRIVATE SUB options()' <-------------------------------------------' actions des options du menu contextuel
DIM sLogoText AS STRING '<---------------------------------------' pour incrustation texte voir plus bas DIM W, H AS FLOAT DIM texte1 AS STRING = sText1 '<----------------------------------' choisir son texte DIM texte2 AS STRING = sText2 '<----------------------------------' choisir son texte
w = PictureBox1.W h = PictureBox1.h
SELECT CASE iDesign '<-------------------------------------------' options de couleur et de taille des fonts pour les design CASE 10, 11, 12 paint.Brush = paint.Color(&000000) paint.font = Font["World of Water, 13,bold"] CASE ELSE paint.Brush = paint.Color(&C0A74C) paint.font = Font["World of Water, 12, "] END SELECT
SELECT CASE iDrap CASE 0 '<----------------------------------------------------' Option 0: ?riting nada sLogoText = "" paint.DrawText(sLogoText, w / 2 - paint.TextSize(sLogoText).w / 2, 134, 10, 10) CASE 1 '<----------------------------------------------------' Option 1: Writing text sLogoText = texte1 paint.DrawText(sLogoText, w / 2 - paint.TextSize(sLogoText).w / 2, 120, 10, 10) sLogoText = texte2 paint.DrawText(sLogoText, w / 2 - paint.TextSize(sLogoText).w / 2, 134, 10, 10) CASE 2 '<------------------------------------------------------' Option 2: ?riting Date sLogoText = Format$(Now, "dd. mmm yyyy") paint.DrawText(sLogoText, w / 2 - paint.TextSize(sLogoText).w / 2, 134, 10, 10) CASE 3 '<----------------------------------------------------' Option 3: writing logo Paint.DrawPicture(Picture["icon:/32/gambas"], w / 2.5, h / 1.9, 50, 50) CASE 4 '<----------------------------------------------------' Option 4 writing logo and date sLogoText = Format$(Now, "dd. mmm yyyy") paint.DrawText(sLogoText, w / 2 - paint.TextSize(sLogoText).w / 2, 134, 10, 10) Paint.DrawPicture(Picture["icon:/32/gambas"], w / 2.3, h / 1.9, 30, 30) END SELECT
END
|
Fonction pour dessiner les aiguilles :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
| PRIVATE FUNCTION Zeichnen(x AS FLOAT, y AS FLOAT, hColor AS INTEGER, iLW AS INTEGER, W AS FLOAT, H AS FLOAT) AS INTEGER '<----------------------------------------------------------------' fonction pour dessiner les aiguilles
paint.Brush = paint.Color(hColor) paint.LineWidth = iLW paint.LineCap = paint.LineCapRound paint.MoveTo((W + 1) / 2, (H + 1) / 2) paint.RelLineTo(x, y) paint.Stroke
END
PRIVATE SUB PaintClock(temps AS DATE) '<----------------------------' peinture des aiguilles
DIM x, y AS SINGLE DIM iRadius AS INTEGER DIM Winkel AS FLOAT DIM W, H AS FLOAT
DIM m AS FLOAT = 0.67 '0.67 'd'origine 'dimensions aiguilles réduites de ce rapport pour les heures DIM p AS FLOAT = 6 '6 =360°/60s 'Tic des minutes ou des secondes correspond à l'angle de rotation en degrés DIM c AS FLOAT = 0.2 '0.2' d'origine 'dimensions aiguilles opposées réduites de ce rapport DIM pk AS FLOAT = 30 '30=60'/2 'Tic des heures correspond à l'angle de rotation en degrés DIM rp AS FLOAT = 1 'rapport du timer 'ne sert à rien mais semble rendre l'image plus fluide
w = PictureBox1.W '<----------------------------------------------' Dimensions en rapport de FMain h = PictureBox1.h '<----------------------------------------------' Dimensions en rapport de FMain
$hPicture = NEW Picture(w, h, TRUE) '<---------------------------' image des aiguilles paint.Begin($hPicture) '<---------------------------------------' début de la peinture
options()'<-------------------------------------------------------' Les options avant le reste pour ne pas couvir les aiguilles
iRadius = $iHandLength[iDesign] '<-------------------------------' Base length of the clock hands
'<----------------------------------------------------------------' Hour Hand Winkel = (Hour(temps) * pk - 90 + 0.5 * Minute(temps)) * rp'<-----' Angle of the hour hand in degrees x = (iRadius * m) * Cos(Rad(Winkel)) '<-------------------------' X-co-ordinate, conversion of degrees to radian y = (iRadius * m) * Sin(Rad(Winkel)) '<-------------------------' Y-co-ordinate, conversion of degrees to radian Zeichnen(x, y, $cHandColor[iDesign], 6, W, H) '<----------------------------------------------------------------' partie opposée aiguille heure Winkel = (Hour(temps) * pk + 90 + 0.5 * Minute(temps)) * rp x = ((iRadius * m) * Cos(Rad(Winkel))) * c y = ((iRadius * m) * Sin(Rad(Winkel))) * c Zeichnen(x, y, $cHandColor[iDesign], 7, W, H) '<----------------------------------------------------------------' Minute Hand Winkel = (Minute(temps) * p - 90) * rp x = (iRadius - 3) * Cos(Rad(Winkel)) y = (iRadius - 3) * Sin(Rad(Winkel)) Zeichnen(x, y, $cHandColor[iDesign], 3, W, H) '<----------------------------------------------------------------' partie opposée aiguille minute Winkel = (Minute(temps) * p + 90) * rp x = (iRadius - 3) * Cos(Rad(Winkel)) * c y = (iRadius - 3) * Sin(Rad(Winkel)) * c Zeichnen(x, y, $cHandColor[iDesign], 4, W, H)
IF bTrotteuse THEN '<-------------------------------------------------------------' Second Hand Winkel = (Second(temps) * p - 90) * rp x = iRadius * Cos(Rad(Winkel)) y = iRadius * Sin(Rad(Winkel)) Zeichnen(x, y, Color.Red, 2, W, H) '<-------------------------------------------------------------' opposit part (short) of the Second Hand Winkel = (Second(temps) * p + 90) * rp x = iRadius * Cos(Rad(Winkel)) * c y = iRadius * Sin(Rad(Winkel)) * c Zeichnen(x, y, Color.Red, 3, W, H) '<-------------------------------------------------------------' Draws a center circle marque le centre paint.Brush = paint.Color(Color.Red) paint.Arc(W / 2, H / 2, 6) ' <---------------------------------' peindre un arc au milieu de rayon paint.Fill '<-------------------------------------------------------------' Draws the center point marque le centre paint.Brush = paint.Color($cHandColor[iDesign]) paint.Arc(W / 2, H / 2, 5) ' <---------------------------------' peindre un arc au milieu de rayon paint.Fill ELSE '<-------------------------------------------------------------' Draws the center point marque le centre paint.Brush = paint.Color($cHandColor[iDesign]) paint.Arc(W / 2, H / 2, 5) ' <---------------------------------' peindre un arc au milieu de rayon paint.Fill ENDIF
paint.End '<----------------------------------------------------' fin de la peinture PictureBox1.Picture = $hPicture '<------------------------------' Transfer painted picture to PictureBox
END
|
Le design de la montre :
1
2
3
4
5
6
7
8
| PRIVATE SUB SetDesign(i AS INTEGER) '<-------------------------------' action sur l'item du menu cliqué
iDesign = i ME.Picture = Picture.Load("Images/Gambas_Clock_" & Format(iDesign, "0") & ".png") '<----'choix de l'image PaintClock(Now) '<----------------------------------------------' mise à jour de l'horloge Module_Settings.StoreClockSettings() '<-------------------------' sauvegarde des settings
END
|
Instanciation :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| PUBLIC SUB _new()
$hConsoleTimer = NEW Timer AS "Timer1" $hConsoleTimer.Delay = 1000 $hConsoleTimer.Enabled = TRUE
paramAiguilles() '<-----------------------------------------------' affichage des aiguilles de l'horloge dimPicture1() '<-------------------------------------------------' dimensions de la pictureBox1
WITH ME .mask = TRUE '<----------------------------------------------' mask transparent du formulaire, ne fonctionne pas sous wayland .w = pictureBox1.w .h = pictureBox1.h .SkipTaskbar = TRUE END WITH
END
|
Ouverture du formulaire principal :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| PUBLIC SUB Form_Open()
Module_Settings.InitDefaultPath '<-------------------------------' Initializing the default path for storing the time zone settings Module_Settings.RestoreClockSettings() '<-------------------------' Restore clock design Module_Settings.RestoreFormPosition(ME) '<----------------------' Restore Form positions
IF NOT Settings.Exist("Clock" & "/Design") THEN '<----------------' affichage premir démarrage iDesign = 0 '<-------------------------------------------------' Design_0 au 1er démarrage iDrap = 0 '<-------------------------------------------------' pas d'affichage de texte au 1er démarrage ENDIF
ME.Picture = Picture.Load("Images/Gambas_Clock_" & Format(iDesign, "0") & ".png") '<-------' chargement du fond de l'horloge
IF NOT Settings.Exist("Clock" & "/Trotteuse") THEN bTrotteuse = TRUE '<-----------------------------------------' pour avoir la trotteuse au démarrage ENDIF
IF NOT Settings.Exist("Clock" & "/Texte1") THEN sText1 = "Gambas" ENDIF
IF NOT Settings.Exist("Clock" & "/Texte2") THEN sText2 = "Buch" ENDIF
IF NOT Settings.Exist("Clock" & "/bAuto") THEN bAuto = FALSE ENDIF
$hConsoleTimer.trigger'<------------------------------------------' Updating the time display at program start
END
|
les actions de la souris sur menu contextuel :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
| PUBLIC SUB PictureBox1_MouseDown()
DIM hContext AS OBJECT '<----------------------------------------' on peut les rendre Static Public DIM hContext1 AS OBJECT '<---------------------------------------' on peut les rendre Static Public DIM hContext2 AS OBJECT '<---------------------------------------' on peut les rendre Static Public DIM hContext3 AS OBJECT '<---------------------------------------' on peut les rendre Static Public DIM hMenuItem AS OBJECT '<---------------------------------------' on peut les rendre Static Public
DIM i AS INTEGER '<----------------------------------------------' variable vraiment locale
hContext = NEW Menu(ME) AS "mnuContext" '<------------------------' menu contextuel principal
hContext2 = NEW Menu(hContext) '<------------------------------' menu contextuel secondaire hContext2.Text = ("Design") hContext2.Picture = Picture["Images/Gambas_Clock_1.png"]
hContext1 = NEW Menu(hContext) '<------------------------------' menu contextuel secondaire hContext1.Text = ("Affichage") hContext1.Picture = Picture["Symbols/clock.png"]
hContext3 = NEW Menu(hContext) '<------------------------------' menu contextuel secondaire hContext3.Text = ("Autres") hContext3.Picture = Picture["icon:/32/administrator"]
hMenuItem = NEW Menu(hContext) AS "mnuEnreg" '<---------------' menu contextuel secondaire hMenuItem.Text = ("Enregistrement") hMenuItem.Picture = Picture["icon:/32/floppy"] hMenuItem.Action = "Enreg"
hMenuItem = NEW Menu(hContext) '<-------------------------------' ligne marquée dans menu hMenuItem.Text = ("")
hMenuItem = NEW Menu(hContext) AS "mnuExit" '<---------------' menu contextuel secondaire hMenuItem.Text = ("Sortie") hMenuItem.Picture = Picture["icon:/32/close"] hMenuItem.Action = "Exit"
FOR i = 0 TO 4
hMenuItem = NEW Menu(hContext1) AS "Option" hMenuItem.Tag = Format(i, "0")
SELECT CASE i CASE 0 hMenuItem.Text = ("Nothing ") '<-----------------------' texte du menu en fonction de l'option hMenuItem.Picture = Picture["icon:/48/cancel"] hMenuItem.Action = "" CASE 1 hMenuItem.Text = ("Text ") hMenuItem.Picture = Picture["icon:/48/font"] hMenuItem.Action = "" CASE 2 hMenuItem.Text = ("Date ") '<-------------------------' texte du menu en fonction de l'option hMenuItem.Picture = Picture["icon:/48/restaurant"] hMenuItem.Action = "" CASE 3 hMenuItem.Text = ("Logo ") '<-------------------------' Logo du menu en fonction de l'option hMenuItem.Picture = Picture["icon:/32/gambas"] hMenuItem.Action = "" CASE 4 hMenuItem.Text = ("Date et Logo ") '<-----------------' Logo du menu en fonction de l'option hMenuItem.Picture = Picture["icon:/32/gambas"] hMenuItem.Action = ""
END SELECT
IF iDrap = i THEN hMenuItem.Checked = TRUE
NEXT
hMenuItem = NEW Menu(hContext3) AS "mnuReveil" hMenuItem.Text = ("Réveil" hMenuItem.Picture = Picture["icon:/32/alarm"] hMenuItem.Action = "Reveil"
hMenuItem = NEW Menu(hContext3) AS "mnuTrotteuse" hMenuItem.Text = ("Trotteuse ") hMenuItem.Picture = Picture["icon:/32/clock"] hMenuItem.Action = "Trotteuse"
hMenuItem = NEW Menu(hContext3) AS "mnuAuto" hMenuItem.Text = ("Auto ") hMenuItem.Picture = Picture["icon:/32/car"] hMenuItem.Action = "Auto" hMenuItem.Tag = "Auto" IF bAuto THEN hMenuItem.Checked = TRUE '<-------------------------' check sur menu Auto en fonction bAuto
hMenuItem = NEW Menu(hContext3) hMenuItem.Text = ("")
hMenuItem = NEW Menu(hContext3) AS "mnuHelp" hMenuItem.Text = ("Aide") hMenuItem.Picture = Picture["icon:/32/help"] hMenuItem.Action = "Help"
FOR i = 0 TO $iNbreImage'<----------------------------------------' Generate the menu items hMenuItem = NEW Menu(hContext2) AS "mnuDesign" hMenuItem.Picture = Picture["Images/Gambas_Clock_" & Format(i, "0") & ".png"] hMenuItem.Action = "clock-design_" & Format(i, "0") hMenuItem.Tag = Format(i, "0") hMenuItem.Text = ("Design " & Format(i, "0")) '<-------------' texte du menu en fonction de i IF iDesign = i THEN hMenuItem.Checked = TRUE NEXT
IF Mouse.Right THEN hContext.Popup '<----------------------------------------------' affichage contextuel du menu avec les items créés ici ENDIF
END
|
Action du Timer :
1
2
3
4
5
6
7
8
9
10
11
12
13
| PUBLIC SUB Timer1_Timer() '<----------------------------------------' mais que fait le Timer
PaintClock(Now) '<----------------------------------------------' il repeint les aiguilles toutes les secondes
IF bAuto THEN '<--------------------------------------------------' changement d'image automatique IF Second(Now) MOD 15 = 0 THEN SetDesign($iCount) INC $iCount IF $iCount > $iNbreImage THEN $iCount = 0 ENDIF ENDIF
END
|
Autres procédures :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
| PUBLIC SUB mnuEnreg_Click() '<---------------------------------------' automatique ou non
Module_Settings.StoreFormPosition(ME) '<-------------------------' sauvegarde avant fermeture Module_Settings.StoreClockSettings()
END
PUBLIC SUB mnuAuto_Click() '<----------------------------------------' automatique ou non
bAuto = NOT bAuto $iCount = iDesign '<----------------------------------------------' mise à jour compteur pour auto Module_Settings.StoreClockSettings() '<-------------------------' sauvegarde des settings
END
PUBLIC SUB mnuTrotteuse_Click()
bTrotteuse = NOT bTrotteuse PaintClock(Now) Module_Settings.StoreClockSettings() '<-------------------------' sauvegarde des settings
END
PUBLIC SUB mnuHelp_Click()
FHelp.Show
END
PUBLIC SUB mnuReveil_Click()
Alarm.Show
END
PUBLIC SUB mnuExit_Click()
Module_Settings.StoreFormPosition(ME) '<-------------------------' sauvegarde avant fermeture Module_Settings.StoreClockSettings() ME.Close()
END
PUBLIC SUB option_Click() '<----------------------------------------' récupération de l'option choisie
iDrap = LAST.tag PaintClock(Now) '<----------------------------------------------' mise à jour de l'horloge
END
PUBLIC SUB mnuDesign_Click()
SetDesign(LAST.Tag)'<---------------------------------------------' Récupération du dernier Item cliqué
END
PUBLIC SUB PictureBox1_MouseDrag() '<-------------------------------' pour draguer
ME.x += Mouse.x - Mouse.startx ME.y += Mouse.y - Mouse.starty
END
|
Explications :
Il s'agit d'une horloge analogique utlisant un formulaire transparent, une image normée en dimension du fond de l'horloge avec les aiguilles créées par code.
Les Settings sont utilisés pour conserver choix du fond de l'horloge ainsi que position de celle-ci sur l'écran.
Ça donne un truc comme ça, avec le menu contextuel :
====================
Navigation :
<-- Liens du Wiki : <--<-- Accueil du WIKI : <-- ====================
Documentation :
==============================