Thread et création dynamique des composants

Soyez le premier à donner votre avis sur cette source.

Vue 7 029 fois - Téléchargée 1 273 fois

Description

Ce code donne un exemple de la création d'un tprogressbar,tbutton et tcheckbox dynamiquement sur la fiche et son controle a travers un thread.
Ceci est mon premier code.
Il manque encore des commmentaires, mais ils seront bientôt.
Je voudrais que vous y jetez un coup d'oeil, corriger des fautes, donner des remarques .....
merci

Conclusion :


Le button create permet de créer un nouveau thread, avec ses composants sur la fiche.
Le button Destroy permet de détruire les threads qui on le checkbox activé.
le zone d'edition contient le temps qui sera pris par chaque thread en millisecondes pour incrementer le progressbar.

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
400
Date d'inscription
samedi 6 août 2005
Statut
Membre
Dernière intervention
11 février 2016
1
Salut,

Je viens de (re)regarder ta source : bon boulot ;).

Je me permets de faire quelques remarques :

*Il aurait été plus judicieux dans un esprit de pédagogie que tu fasses deux sources :
-Une sur la création dynamique d'un composant.
-Une sur la création et utilisation d'un Thread.
En effet un débutant risque d'etre un peu paumé ;).

*Tu devrais profiter de ce post pour faire un tuto sur les Threads et sur la création des composants. On manque cruellement de tutos sur CS et les meilleurs tutos de débutants sont ceux faits par les débutants (je dis ca car il y a deja des tutos sur les composants mais ils sont à mon gout d'un niveau et d'une formulation peu accessible pour les débutants).

Tu peux encore proposer des sources comme ca : je suis preneur ^^.

A+
Messages postés
4297
Date d'inscription
samedi 19 janvier 2002
Statut
Modérateur
Dernière intervention
9 janvier 2013
29
Mauricio : le test que tu donnes est un peu faussé.
Je m'explique : quand les threads secondaires doivent se synchroniser avec le thread principal et que ce dernier est bloqué, comment veux-tu que l'interface soit réactive ?
A moins de modifier le code de la procédure Sleep, on ne peut pas faire autrement. Mais rien ne t'empêche d'écrire ta propre procédure équivalente à Sleep et d'y inclure un appel à Application.ProcessMessages.
Messages postés
2106
Date d'inscription
mardi 10 décembre 2002
Statut
Modérateur
Dernière intervention
15 décembre 2014
5
Salut Bhmalek,
ta source m' a interessé parce que Delphiprog et moi même avons étudié les threads (pour faire une boite de dialogue avec gauge pour faire patienter l' utilisateur ...) et que nous sommes tombés sur un os.
Malheureusement tu ne résouds pas non plus le problème qui est, s' il existe un autre processus bloquant, celui-ci empêchera tes gauges d' avancer...

Voilà comment tu peux tester ce que je dit:
Mets un bouton sur ta form avec le code suivant:

procedure TForm1.SpeedButton1Click(Sender: TObject);
var i: integer;
begin
for i := 0 to 99 do
sleep(100);
end;

Ensuite tu compiles et tu executes une ou 2 gauges et tu cliques sur le bouton que je te propose et tu verras que ta gauge s' arrête tans que le code dans le bouton n' est pas fini...

Malheureusement nous n' avons pas trouvé de solution à ce problème.
Ici on pourrait résoudre le problème gràce à l' utilisation de application.ProcessMessages dans le For mais cela serait impossible lors de l' execution d' un code SQL par exemple.

Très bonne 1ere source tout de même !!!

A+
Messages postés
4297
Date d'inscription
samedi 19 janvier 2002
Statut
Modérateur
Dernière intervention
9 janvier 2013
29
Très bon travail, bien au contraire.

Voici quelques pistes d'améliorations :
- tu masques les problèmes de portée en déclarant la classe TMaTache dans la même unité que TForm1. En agissant ainsi, le constructeur que tu as déclaré en protected devient accessible.
Pour mieux structurer ton travail, je te recommande de déclarer TMaTache dans une autre unité comme ceci :

unit UMaTache;

interface

uses
Classes, SysUtils, StdCtrls, ComCtrls, Controls;

type
TMaTache = class(TThread)
private
barre: TProgressbar;
button: TButton;
vitesse: integer;
pause: boolean;
protected
procedure buttonclick(Sender: TObject);
procedure construire(parent: TWinControl; y: integer);
procedure execute; override;
procedure detruire(Sender: tobject);
public
boite: TCheckBox;
constructor Create(parent: TWinControl; y, v: integer);
end;

implementation

{ TMaTache }

procedure TMaTache.buttonclick(Sender: TObject);
begin
if barre.position = barre.Max then
begin
barre.Position := 0;
pause := false;
end
else
Pause := not Pause;

if pause then
button.Caption := 'Continue'
else
button.Caption := 'Stop';
end;

procedure TMaTache.construire(parent: twincontrol; y: integer);
begin
barre := tprogressbar.Create(parent);
barre.Parent := parent;
barre.SetBounds(30, y, 300, 20);

boite := tcheckbox.Create(parent);
boite.Parent := parent;
boite.SetBounds(10, y, 14, 17);
boite.checked := false;
boite.Caption := '';

button := tbutton.Create(parent);
button.Parent := parent;
button.SetBounds(340, y-5, 70, 30);
button.Caption := 'Stop';
button.OnClick := buttonclick;

pause := false;
end;

constructor TMaTache.Create(parent: twincontrol; y, v: integer);
begin
inherited create(false);
FreeOnTerminate := true;
construire(parent, y);
vitesse := v;
OnTerminate := detruire;
end;

procedure TMaTache.detruire(Sender: tobject);
begin
barre.Free;
button.Free;
boite.Free;
inherited terminate;
end;

procedure TMaTache.execute;
var
i: integer;
begin
repeat
sleep(vitesse);
i := barre.Position;
if not pause then
barre.Position := i + 1;

if i = Barre.Max then
button.Caption := 'Restart';
until terminated;
end;

end.

Au passage, tu auras remarqué quelques restructurations, simplifications et optimisations du code :o).
En effet, à chaque fois que tu modifies les propriétés Top, Left, Height ou Width d'un composant visuel, ce dernier est redessiné. Avec le méthode SetBounds, il n'est redessiné qu'une fois.
A noter aussi que seuls le constructeur et la propriété Boite ont besoin d'être exposés à l'extérieur de la classe et doivent donc figurer en section Public.

Au niveau de l'unité Unit1 (maintenant allégée), on trouve le code restant avec quelques réaménagements commentés plus bas :
type
TForm1 = class(TForm)
btnCreate: TButton;
btnDestroy: TButton;
Edit1: TEdit;
XPManifest1: TXPManifest;
procedure FormCreate(Sender: TObject);
procedure btnCreateClick(Sender: TObject);
procedure Edit1Change(Sender: TObject);
procedure btnDestroyClick(Sender: TObject);
private
function FirstFree: integer;
{Redimensionne la fenêtre en fonction du nombre
de Threads actifs}
procedure ResizeWindow(Nombre: integer);
public
{ Public declarations }
end;

var
Form1: TForm1;


implementation

uses UMaTache;

{$R *.dfm}
var
MesTaches: array of TMaTache;

procedure TForm1.FormCreate(Sender: TObject);
begin
//inutile => setlength(MesTaches, 0);
end;

procedure TForm1.btnCreateClick(Sender: TObject);
var
i: integer;
begin
i := length(MesTaches);
if FirstFree = 0 then
begin
setlength(MesTaches, i + 1);
ResizeWindow(i);
end
else
i := FirstFree - 1;

MesTaches[i] := TMaTache.Create(Self, ((30 * i) + 10), StrToIntDef(edit1.Text, 0));
end;

procedure TForm1.Edit1Change(Sender: TObject);
var
i: integer;
begin
i := StrToIntDef(edit1.Text, 0);
btnCreate.Enabled := (i > 0) and (i < 10000);
end;

function TForm1.FirstFree: integer;
var
i: integer;
begin
result := 0;
for i := length(MesTaches) - 1 downto 0 do
if not assigned(MesTaches[i]) then
result := i + 1;
end;

procedure TForm1.btnDestroyClick(Sender: TObject);
var
i, j: integer;
begin
i := length(MesTaches);
if i = 0 then
exit;
for j := 0 to i - 1 do
begin
if MesTaches[j] = nil then
continue;
if MesTaches[j].boite.checked then
begin
MesTaches[j].Terminate;
MesTaches[j] := nil;
end;
end;
j := i - 1;
while MesTaches[j] = nil do
begin
dec(i);
dec(j);
end;
setlength(MesTaches, i);

ResizeWindow(i);
end;

procedure TForm1.ResizeWindow(Nombre: integer);
begin
Height := 90 + Nombre * 30;
btnCreate.Top := Height - 60;
btnDestroy.Top := Height - 60;
edit1.Top := Height - 58;
end;

Observations :
- bien que ce ne soit pas une erreur, il est habituel de déclarer tes propres routines en section Public ou Private et non dans la section par défaut (bien que cette dernière soit en réalité de portée Public).
- le code dans Edit1Change a été simplifié
- le code dupliqué redimensionnant la fenêtre Form1 a été déplacé dans une méthode nommée ResizeWindow

En déclarant chaque classe dans son unité propre, c'est aussi le meilleur moyen de permettre sa réutilisation.
Si je n'avais qu'une critique à faire, ce serait celle-ci.

Globalement, tu as bien travaillé et tu es sur la bonne voie ;o)
Messages postés
384
Date d'inscription
vendredi 18 juin 2004
Statut
Membre
Dernière intervention
7 mai 2009

Non, c'est pas decevant, je trouve ça pas mal ;-)
C'est une illustration de l'utilisation des thread et de la création de compo à la volée -> pas mal.

7/10 :)
Afficher les 6 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.