02. januar 2009 - 12:50Der 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?
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.
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.
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>).
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.
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;
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.
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 :-|
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?
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).
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);
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.
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.
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 :-)
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;
Shit! Ramte knappen. Ville nok holde de 5 tabeller på formen men lade dem trække på forbindelsen i datamodulet.
Synes godt om
Ny brugerNybegynder
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.