Avatar billede hugopedersen Nybegynder
02. januar 2009 - 12:50 Der er 16 kommentarer og
2 løsninger

Sende formnavn og controlnavn til funktion

Sikkert et basic spørgsmål men alligevel:
Jeg har nogle forms hvor jeg laver en forbindelse til min MySQL server (bruger Devart MyDAC) og det virker sådan set fint nok, men jeg ville gerne minimere min kode lidt og så lave en generic funktion der connecter til MySQL. Til det skal jeg bruge en funktion der kan kaldes med navnet på den control der styrer MySQL forbindelsen og måske også navnet på formen.
Hvordan sender man de 2 ting til en funktion og arbejder videre med dem i funktionen?
Avatar billede kroning Nybegynder
02. januar 2009 - 12:59 #1
function GørTing(MyDAC : TMyDAC; Formen : TForm) : integer;
begin

end;
Avatar billede kroning Nybegynder
02. januar 2009 - 13:04 #2
Men det bedste vil vel være kun at have en enkelt TMyConnection som så benyttes af alle forme i stedet for at have en TMyConnection på hver eneste form.
Avatar billede hugopedersen Nybegynder
02. januar 2009 - 13:18 #3
Det skal jeg lige have afprøvet. Men jeg er lige blevet tilsagt af lillemor at min tilstedeværelse er ønskelig - og så er det med at få fingeren ud :-)

Jeg vender tilbage senere.

PS: Du kan have ret i at det ville være det smarteste med kun 1 connection. Men jeg kan ikke lige gennemskue hvordan jeg laver det nemmest. Og desuden har jeg bruge for at connecte til 2 forskellige databaser da nogle data jeg bruger kommer fra en anden db. Alternativt skal jeg have fundet ud af at lave en automatisk overførsel fra den ene db til den anden. Men det er et MySQL spørgsmål.
Avatar billede hrc Mester
02. januar 2009 - 13:24 #4
Du laver en TDataModule hvorpå du placerer 1 eller 2 "connection"-komponenter. Ved start placerer du DM'et før main eller opretter (og sletter) det i maiformen. Alle forme der bruger den skal inkludere DM'et (genvejstasten er <Alt-F11>).
Avatar billede hrc Mester
02. januar 2009 - 13:25 #5
Glemte at sige, at grunden til den skal oprettes tidligt er, at forbindelsen skal oprettes (evt. vha. DM'ets OnCreate og OnDestroy events).
Avatar billede hugopedersen Nybegynder
02. januar 2009 - 17:15 #6
hrc> jeg kan meget nemt se fidusen i det du siger. Men da jeg har flere queries fra samme form så skal jeg vist lige have fundet et stykke papir og have tegnet noget ned før jeg går igang med det.  Men det skal da forsøges.
Avatar billede hrc Mester
03. januar 2009 - 01:30 #7
Der kan du overveje at have et DM som indeholder databaseforbindelserne og et som vedrører de queries der er på formen. Sidstnævnte linker til det første for at få forbindelsen. Det eneste du stadig behøver på formen er eventuelle TDataSource-komponenter.
Har i øvrigt tit haft nytte af små funktioner der returnerede et query-objekt eller en stored procedure:

function DM.CreateQuery: TDevartSQL;
begin
  result := TDevartSQL.Create(nil);
  result.DataConnection := xyzConnection;
end;

... og næsten tilsvarende for SP'en.

I det hele taget prøver jeg at holde så meget lokale i metodernes "scope" så de ser næsten altid sådan ud:

procedure TForm1.DoThisAndDoThat(Sender: TObject);
var
  Query: TDevartSQL;
begin
  Query := DM.CreateQuery;
  try
    Query.SQL.Add('...');
    ...
    Query.Open; // alternativt: ExeSQL
    while not Query.Eof do
    begin
      Query.Next;
    end;
  finally
    Query.Free;
  end;
end;
Avatar billede hugopedersen Nybegynder
04. januar 2009 - 12:30 #8
Status:
Jeg har gjort det at jeg placerer connection komponenten på min main form da den altid er fremme og så connecter jeg ved FormCreate og disker ved FormClose - det må være OK.

Der ud over arbejder jeg lidt med HRC's forslag med et modul til diverse queries.

Så jeg har snuppet lidt fra begge forslag så et par svar.
Avatar billede hrc Mester
04. januar 2009 - 18:04 #9
Jeg kan på det stærkeste fraråde dig at have tabeller placeret på mainformen som andre forme bruger. For det første får du cirkulære referencer (hvor mainform "uses" den subforme og subformene "uses" mainformen for at få fat på connection-komponenten. Den rigtige løsning er et TDataModule.

Desuden har jeg oplevet at forbindelsen mellem TDataSet (TQuery eller TTable) og/eller TDataSource blev mistet, medmindre mainformen var åben hele tiden. Ret surt at sende et program med 240 forme og så opdage at 2-3 af den ikke længere peger på en tabel i mainformen!

Flyt den dog over i en TDataModule, det er ikke svært, og link til den derfra. Du undgår cirkulære referencer og dit program bliver meget pænere og noget lettere at debugge. Nu er du advaret :-|
Avatar billede hugopedersen Nybegynder
04. januar 2009 - 18:44 #10
Det er ikke usandsynligt at du har ret. I dette tilfælde er jeg dog sikker på at mainformen er åben hele tide for hvis ikke den er det, så er programmet ikke startet.

Jeg vil prøve at arbejde lidt videre med din ide og se om jeg kan få det til at spille.
Har du evt. et eksempel på sådan et modul du har lavet man kunne se nogle screendumps fra?
Avatar billede kroning Nybegynder
05. januar 2009 - 05:18 #11
k
Avatar billede hrc Mester
05. januar 2009 - 08:53 #12
Datamodulet er en slags "form" hvor man placerer de ikke-synlige komponenter. Det er også for at holde den rigtige form fri for en masse distraherende komponenter. I Delphi finder man den ved "New\Other" og der "Delphi Files".

Du skriver at du holder mainformen åben i hele programmet - ja, naturligvis gør du det. Har ikke hørt om nogen der byttede mainformen ud og tvivler om man kan (tror Application.MainForm er skrivebeskyttet).
Avatar billede hrc Mester
05. januar 2009 - 09:16 #13
Hvis det ønskes kan jeg også sende DFM-filerne, men det burde ikke være nødvendigt her:

Mainformen:
-----------

type
  TfrmMain = class(TForm)
    btnSubForm: TButton;
    procedure btnSubFormClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
  public
  end;

var
  frmMain: TfrmMain;

implementation

uses FSubForm, UDM;

{$R *.dfm}

procedure TfrmMain.btnSubFormClick(Sender: TObject);
begin
  // Kan ikke lade være med at bruge denne lidt kryptiske one-liner. Det kan lade
  // sig gøre fordi "Action := caFree" i subformen. Den sørger for at frigive sig selv.
  TfrmSubForm.Create(self).ShowModal;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  DM := TDM.Create(self,'server','database','login','password');
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  DM.Free;
end;

Datamodulet:
------------

type
  TDM = class(TDataModule)
    ADOConnection: TADOConnection;
    procedure DataModuleDestroy(Sender: TObject);
  private
  public
    // Modificerer lige constructoren så den passer til et generisk eksempel (paradigme)
    constructor Create(aOwner: TComponent; const aServer, aDatabase, aLogin, aPassword: string); reintroduce;
    function CreateQuery: TADOQuery;
  end;

var
  DM: TDM;

implementation

{$R *.dfm}

{ TDM }

constructor TDM.Create(aOwner: TComponent; const aServer, aDatabase, aLogin, aPassword: string);
var
  ConnectionString : TStringList;
begin
  inherited Create(aOwner);

  ConnectionString := TStringList.Create;
  try
    ConnectionString.Delimiter := ';';
    ConnectionString.StrictDelimiter := true;
    ConnectionString.QuoteChar := #0;

    ConnectionString.Add(      'Provider=SQLOLEDB.1');
    ConnectionString.Add(format('Data Source=%s',[aServer])); // Server
    ConnectionString.Add(format('Initial Catalog=%s',[aDatabase])); // Database
    ConnectionString.Add(format('User ID=%s',[aLogin])); // Userid
    ConnectionString.Add(format('Password=%s',[aPassword])); // password
    ConnectionString.Add(      'Persist Security Info=True');
    ConnectionString.Add(      'Use Procedure for Prepare=1');
    ConnectionString.Add(      'Auto Translate=True');
    ConnectionString.Add(      'Packet Size=4096');
    ConnectionString.Add(      'Use Encryption for Data=False');
    ConnectionString.Add(      'Tag with column collation when possible=False');

    ADOConnection.ConnectionString := ConnectionString.DelimitedText;
    ADOConnection.Open;
  finally
    ConnectionString.Free;
  end;
end;

function TDM.CreateQuery: TADOQuery;
begin
  result := TADOQuery.Create(nil);
  result.Connection := ADOConnection;
end;

procedure TDM.DataModuleDestroy(Sender: TObject);
begin
  ADOConnection.Close;
end;

SubFormen:
----------

type
  TfrmSubForm = class(TForm)
    DBGrid: TDBGrid;
    dsData: TDataSource;
    qData: TADOQuery;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
  public
  end;

implementation

uses UDM;

{$R *.dfm}

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

procedure TfrmSubForm.FormCreate(Sender: TObject);
begin
  qData.Open;
end;

procedure TfrmSubForm.FormDestroy(Sender: TObject);
begin
  qData.Close;
end;
Avatar billede hugopedersen Nybegynder
05. januar 2009 - 12:47 #14
Det skal jeg have prøvet. Jeg er lige startet på arbejde efter ferie i dag, så skidtet ligger lidt højt på mit bord :-)

Jeg kan dog ikke helt se hvad det er du laver i den der subform. Men det er nok lidt forskelligt om det er ADO du bruger til din M$ SQL eller det er MyDAC som jeg bruger til MySQL.
Avatar billede hrc Mester
06. januar 2009 - 09:24 #15
Subformen indeholder en TDBGrid som kobler sig til en TDataSource der igen hægter sig på en TADOQuery ('select * from <table>'). Alle disse komponenter ligger på SubFormen. TADOQuery får sin forbindelse (Connection) fra DM.ADOConnection. Kunne godt have valgt at placere min TDataSource på TDataModulet, men nogle gange kan det være mere praktisk at have den på formen.
Avatar billede hugopedersen Nybegynder
06. januar 2009 - 09:39 #16
Det der forvirrede mig er nok
function TDM.CreateQuery: TADOQuery;
begin
  result := TADOQuery.Create(nil);
  result.Connection := ADOConnection;
end;
i datamodulet - det er da en query.

Men jeg tror jeg har fået det til at spille nu med connection i datamodul. Jeg skal så bare se om det er noget at flytte min TMyQuery der over også. Jeg har en form der bruger 5 forskellige tabeller alt efter hvilken TAB der er aktiv og det er mange bytes ekstra der kommer i koden for at flytte :-)
Avatar billede hrc Mester
06. januar 2009 - 09:54 #17
Jeg ville bare demonstrere den lille smarte makro.

Det er ikke så tit jeg placerer TADOQuery'er på formen. Det er kun til listerder vises op skærmen osv. Har jeg en knap der gør et eller andet, så bliver det sådan her:
procedure .. (const aGruppeID: integer);
var
  Query: TADOQuery;
begin
  Query := DM.CreateQuery; // Her bruger jeg den. Har tilsvarende for Stored Procs'
  try
    Query.SQL.Clear; // Unødvendigt, men en del af rutinen
    Query.SQL.Add('select *');
    Query.SQL.Add('  from personale');
    Query.SQL.Add('  where (gruppeid = :gruppeid)');
    Query.SQL.Add('  order by navn');
    Query.Parameters.ParamByName('gruppeid').AsInteger := aGruppeID;
    Query.Open;
    while not Query.Eof do
    begin
      // Lav et eller andet med data..
      Query.Next;
    end;
  finally
    Query.Free;
  end;
end;
Avatar billede hrc Mester
06. januar 2009 - 09:55 #18
Shit! Ramte knappen. Ville nok holde de 5 tabeller på formen men lade dem trække på forbindelsen i datamodulet.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester