![]() |
Spalten in einem DBGrid verschieben und auch sortieren!
Ich hab da ein kleines problem:
Ich habe im Formular unter 'type' folgendes eingegeben:
Code:
und weiters
THackAccess = class(TCustomGrid);
Code:
Wenn ich das Prog. jetzt starten möchte, kommt eine Fehlermeldung:
procedure MoveDBGrid1Columns(DBGrid1: TDBGrid; FromColumn, ToColumn: Integer);
begin THackAccess(DBGrid1).MoveColumn(FromColumn, ToColumn); end; ':'erwartet, '=' gefunden Das ist bei der Zeile unter Type. Was mach ich da falsch? Ich möchte, dass der User die Colums im DBGrid verschieben kann, wie er möchte. Weiters hab ich noch ne frage: In den Colums werden Datensätze wie z.B. Name Vorname usw angezeigt. Wie kann ich es erstellen, dass wenn ein User auf eine Columsüberschrift klickt, die Daten entweder von A-Z oder von Z-A sortiert werden. (Dies soll für jede columne so sein!) |
Hi m-werk,
irgendwie muss das was mit der type-Deklaration faul sein. Poste mal die Deklaration vor THackAccess, ich vermute, das fehlt ein end oder etwas ähnliches. MfG, d3g |
Die Deklaration hab ich ja eh schon gepostet! oder nicht?
Ich habe unter type das stehen:
Code:
und noch den code der procedure, den ich vorher hineingeschrieben habe.
THackAccess = class(TCustomGrid);
Hab ich da was vergessen? |
Hi m-werk,
Zitat:
d3g |
Code:
type
TKundenDruckMenue = class(TForm) THackAccess = class(TCustomGrid) Button2: TButton; DBGrid1: TDBGrid; Label1: TLabel; .... usw. |
Hi m-werk,
so muss es heißen:
Code:
Evtl. THackAccess vor TKundenDruckMenue stellen.
type
TKundenDruckMenue = class(TForm) Button2: TButton; DBGrid1: TDBGrid; Label1: TLabel; .... usw. end; THackAccess = class(TCustomGrid); MfG, d3g |
DANKE, das mit dem Code nach dem end. funktioniert spitze. Ich kann jetzt die Spalten bewegen, wie ich möchte.
Eine sache habe ich dabei noch bemerkt. Wenn ich jetzt die Spalten vertausche, und dann das programm nochmal starte, ist alles wieder so, wie es vorher war. Das vertauschen wird nicht gespeichert. Wie kann ich dass den lösen. Weiters: Wie kann ich jetzt noch sortieren? Wenn ich auf eine Spaltenüberschrift klicke, dann soll sortiert werden. Entweder von A-Z oder von Z-A. Kannst du mir da auch noch helfen? |
Sorry, ich benutze im Moment nur D6 Personal und das siehts mit TDBGrid ein bisschen mager aus...
MfG, d3g |
Das DBGrid dient doch nur der Darstellung der Daten, das heißt die Sortierung müßte IMHO mit einer Abfrage gemacht werden.
|
IMHO? was bedeutet das?
Wie könnte denn so eine Abfrage aussehen? Wie kann ich auch die Spaltenverschiebung speichern, so dass beim nächsten Start des Prog. nicht wieder die urspüngliche Einstellung angezeigt wird? |
Hi m-werk,
IMHO: in my humble opinion. Was das Speichern angeht, könntest du ja die Property Cols[] abspeichern und neu laden. MfG, d3g |
IMHO = in my humble opinion = in meiner bescheiden Meinung
Keine Ahnung wie so eine Abfrage auszusehen hat. Von Datenbanken habe ich keinen Schimmer. Ich weiß nur so viel, dass das DBGrid nicht dazu da ist Daten zu manipulieren, zu filtern etc., dazu gehört auch das Sortieren. Bitte korrigieren, wenn ich falsch liegen sollte, aber ich bin mir hier ziemlich sicher. Die Abfrage hängt auch von der Datenbank ab: mySQL, BDE, Paradox. Access, ... |
Aua, es handelt sich, um ein DB- kein StringGrid.
Bitte mein obiges Posting vergessen... MfG, d3g |
Hallo m-werk,
zunächst einmal zum Thema Sortierung: Es gibt da grundsätzlich zwei Möglichkeiten. Die erste ist das Arbeiten mit Indices. Dazu legst du für alle möglichen Sortierungen Sekundärindices an. Dann wählst du einfach den gewünschten Index aus und die Sortierung funktioniert automatisch. Die zweite Möglichkeit ist eine Abfrage zu erstellen in der Form:
Code:
Diese Abfrage packst du in eine TQuery Kompo und führst diese durch "Open" aus.
SELECT * FROM Kunde ORDER BY Vorname DESC
Zum Thema "Speichern der Reihenfolge der Felder". Dazu würde ich die Eigenschaft "Index" der TField Objekte auslesen und in einer Ini-Datei speichern. Beim Starten der Anwednung liest du diese Werte wieder aus und weist sie der Index-Eigenschaft wieder zu. |
Danke für den Tip beim Sortieren. Ich werde die 2. Variante nehmen.
Mit dem Speichern der Spaltenpositionen komm ich nicht so zurecht. Kannst du mir dabei bitte helfen? |
Hallo m-werk,
sowohl TQuery als auch TTable sind (indirekt) von TDataSet abgeleitet. Dort ist die Eigenschaft Fields definiert. Je nachdem wann du die Reihenfolge der Felder im Grid speichern willst, könntest du in der entsprechenden Ereignismethode folgendes schreiben:
Code:
Das Einlesen läuft analog, z.B. in der OnActivate Methode.
var
Ini : TIniFile; i : Integer; reihenfolge : String; ... try Ini := TIniFile.Create(ChangeFileExt(Application.ExeName), '.INI'); reihenfolge := ''; for i := 0 to MyTable.FieldCount-1 do reihenfolge := reihenfolge+IntToStr(MyTable.Fields[i].Index)+';' Ini.WriteString('Grid', 'Reihenfolge', reihenfolge); Ini.Free; except ... Ist zwar nicht getestet, sollte aber funktionieren. |
OK, das mit dem Speichern habe ich jetzt hinbekommen. Funktioniert tatellos.
Es ist nur noch ein Problem: Im DBGrid müssen erst Datensätze stehen, dannach kann ich die Spalten verschieben und die Position wird dann erst in der INI gespeichert. Vielleicht könnte man das auch dann machen, wenn keine Daten im Grid stehen. Aber nun zum nächsten. Wie rufe ich die Position der Spalten beim öffnen des Formulares wieder auf, die in der INI stehen? |
Sollte eigentlich. Aber dein gesamter try-Block ist Mist. Bei einem Fehler wird Ini nicht wieder freigegeben usw.
So ist es besser:
Code:
Eventuell behebt das auch dein Poblem.
[b]procedure[/b] TKundenDruckMenue.FormClose(Sender: TObject;
[b]var[/b] Action: TCloseAction); [b]var[/b] Ini : TIniFile; i : Integer; reihenfolge : [b]String[/b]; [b]begin[/b] reihenfolge := ''; [b]for[/b] i := 0 [b]to[/b] DBGrid1.FieldCount-1 [b]do[/b] reihenfolge := reihenfolge+IntToStr(DBGrid1.Fields[i].Index)+';'; Ini:=TIniFile.Create(ExtractFilePath(Application.ExeName)+ 'Einstellungen.ini'); [b]try[/b] Ini.WriteString('Grid', 'Reihenfolge', reihenfolge); [b]finally[/b] Ini.Free; [b]end[/b]; [b]end[/b]; |
Danke für die verbesserung, aber das Problem ist damit nicht behoben!
|
Wärend ich gepostet habe, hast du doch geschrieben, dass es jetzt gehen würde oder was oder wie oder wo oder...
|
Ja sicher funktioniert es, aber nur dann wenn Daten im Grid stehen. Kann man das auch irgendwie lösen, auch wenn keine Daten im Grid stehen?
Das ist aber nicht so wichtig. Wichtig wäre Wie kann ich jetzt die Spaltenposition beim öffnen des Formulares aus der INI lesen? |
Hallo m-werk,
was genau meinst du mit Zitat:
Nun zum Lesen der IniDatei:
Code:
Hab ich zwar nicht getestet, aber so ähnlich sollte das wohl aussehen.
var
Ini : TIniFile; i, posi : Integer; reihenfolge : String; begin reihenfolge := ''; try Ini:=TIniFile.Create(ExtractFilePath(Application.ExeName)+ 'Einstellungen.ini'); reihenfolge := Ini.ReadString('Grid', 'Reihenfolge', ''); finally Ini.Free; end; try posi := Pos(reihenfolge, ';'); i := 0; while posi > 0 do begin DBGrid1.Fields[i].Index := StrToInt(Copy(reihenfolge, 1, posi-1)); Delete(reihenfolg, 1, posi); posi := Pos(reihenfolge, ';'); Inc(i); end; except on E:exception do ShowMessage('Fehler in der Ini-Datei:'#13 +E.Message); end; end; |
Zitat:
Danke für den Code, ich werde ihn am Wochenende testen. |
Herr im Himmel. :evil:
Nehmt doch endlich mal das TIniFiel.Create aus dem try-Block raus! Lest ihr euch denn nicht die Warnungen durch, die der Kompiler ausgibt? :roll: Wenn ich das so mache wie ihr, steht da immer: Zitat:
Hier noch mal wie es richtig geht:
Code:
[b]procedure[/b] TForm1.Button1Click(Sender: TObject);
[b]var[/b] ini: TiniFile; [b]begin[/b] ini := Tinifile.Create(ChangeFileExt(ParamStr(0), '.ini')); [b]try[/b] ini.WriteString('Programm', 'Pfad', ParamStr(0)); [b]finally[/b] ini.Free; [b]end[/b]; [b]end[/b]; |
Jaja, :oops: is ja schon gut... :mrgreen:
|
Na dann wollen wir mal hoffen, dass das jetzt angekommen ist. Wenn ich das noch mal bei dir sehen, dann schreibst du mir hundertmal:
Zitat:
|
@Luckie: schon mal profilaktisch...
Code:
:shock:
for i := 1 to 100 do
Writeln('TIni.Create kommt nicht in den try-Block. '); |
@m-werk,
ich hab mir das jetzt mal angeschaut, es funktioniert auch mit leeren Tabellen, aber nicht mit GESCHLOSSENEN Tabellen. Das ist ja auch klar, weil dann die Verbindung zur Tabelle nicht besteht. Du musst also sicher stellen, dass die Tabelle geöffnet ist, wenn die Reihenfolge geschrieben werden soll. Auch beim Lesen und zuweisen der Indices muss die Tabelle geöffnet sein. |
Hi, was soll ich den genau tun, damit die Tabelle offen ist?
|
Hallo m-werk,
grundsätzlich natürlich mit MyTable.Open. Irgendwo wird ja die Tabelle geöffnet, entweder schon im Objektinspektor oder irgendwo im Programm. Dann lässt du einfach das Schließen der Tabelle nicht zu. |
Hi, das DBGrid greift auf eine ADOQuery zu. Ich habe in der ADOQuery einen SQL-String: GROUP BY KundenNr. Diesen brauche ich, da ich ja einige Abfragen in dem Formular habe, die dann in dem Grid ersichtlich sind. Wenn ich das Formular öffne, dann ist das Grid leer. Das soll auch so sein, da dieses Formular nur zum Filtern von Daten gedacht ist.
Ich hab aber auch schon probiert, ADOQuery.Open. Da muß ich aber zuerst eine SQL wie z.B. SELECT, INSERT usw. einfügen. Wenn ich so etwas einfüge, dann sehe ich jetzt beim öffnen Alle Kunden im Grid. (Zeichen dafür, dass die Tabelle offen ist.) Aber das mit dem Lesen der INI, wo ich dann die Reihenfolge drinn habe, funktioniert nicht. Das Speichern geht super. Kann man das so lösen, dass die Tabelle offen ist, wenn ich das Formular öffne, ohne dass irgendwelche Daten im Grid stehen? |
Hi Leute, hat keiner von euch eine Idee, wie Ich das obrige Problem lösen kann?
Wäre euch zu dank verpflichtet, wenn ihr mir helfen könnt! |
Hallo m-werk,
ich könnte mir vorstellen, dass du ein SELECT Statement benutzt, dass die korrekte Struktur, also alle die Felder enthält, die normalerweise angezeigt werden sollen, erzeugt, aber keine Datensätze enthält. Z.B.: SELECT * FROM Personen WHERE ID = 0, wobei eine ID 0 nicht existiert. So erhälst du eine leere Datenmenge. Probier das doch mal aus. |
Hi, hab nicht ganz kapiert, was du meinst.
Für die Anzeige im DbGrid hab ich folgenden Code zusammengeschnipselt:
Code:
Kannst du damit was anfangen?
procedure TKundenDruckMenue.Button6Click(Sender: TObject);
var cSql : String; begin with ADOQuery1 do begin Active := False; Sql.Clear; if CheckBox1.Checked then begin cSql := 'Select DISTINCT KundenNr, Anrede, Titel, Vorname, Nachname, Straße, PLZ, Ort, Geburtsdatum, Land, Beruf, Telefon, Mobil, Fax, email FROM Kundendaten'; end else if (allekunden.Checked = False) and (email.Checked = False) and (lv.Checked = False) and (flv.Checked = False) and (df.Checked = False) and (ff.Checked = False) and (sv.Checked = False) and (bsp.Checked = False) and (sto.Checked = False) and (mk.Checked = False) then begin if Trim(Edit1.Text) = '' then begin ShowMessage('Bitte geben Sie einen Wert ein!'); exit; end; cSql := 'Select DISTINCT KundenNr, Anrede, Titel, Vorname, Nachname, Straße, PLZ, Ort, Geburtsdatum, Land, Beruf, Telefon, Mobil, Fax, email FROM Kundendaten where (' + ComboBox1.Text + ' like ' + QuotedStr (Edit1.Text + '%') +')' end else cSql := 'Select DISTINCT A.KundenNr, A.Anrede, A.Titel, A.Vorname, A.Nachname, A.Straße, A.PLZ, A.Ort, A.Geburtsdatum, A.Land, A.Beruf, A.Telefon, A.Mobil, A.Fax, A.email FROM Kundendaten A LEFT JOIN Geschaeftsdaten B ON A.KundenNr = B.KundenNr '; if (allekunden.Checked) and (flv.Checked) and (lv.Checked) and (df.Checked) and (ff.Checked) and (sv.Checked) and (bsp.Checked) and (sto.Checked) then cSql := cSql + ' AND ( [A.ist Kunde] = True OR [B.flv] = True OR [B.lv] = True OR [B.df] = True OR [B.ff] = True OR [B.sv] = True OR [B.bsp] = True OR [B.sto] = True OR [A.email] = True OR [B.eigengeschaeft] = True)' else if allekunden.Checked then cSql := cSql + ' WHERE A.[ist Kunde] = True' else if flv.Checked then cSql := cSql + ' WHERE B.[flv] = True' else if lv.Checked then cSql := cSql + ' WHERE B.[lv] = True' else if df.Checked then cSql := cSql + ' WHERE B.[df] = True' else if ff.Checked then cSql := cSql + ' WHERE B.[ff] = True' else if sv.Checked then cSql := cSql + ' WHERE B.[sv] = True' else if bsp.Checked then cSql := cSql + ' WHERE B.[bsp] = True' else if sto.Checked then cSql := cSql + ' WHERE B.[sto] = True' else if mk.Checked then cSql := cSql + ' WHERE B.[eigengeschaeft] = True'; if email.Checked then cSql := cSql + ' WHERE TRIM (A.[email]) <> ' + QuotedStr (''); Sql.Add(cSql); Open; end; end; |
Hi M-werk,
habe das Thema gerade gesehen, bin an etwas weit entfent ähnlichem dran.
Code:
Was sind denn das für [] ?? Ist doch SQL oder hab ich mich verlesen ? Der Code sieht jedenfalls ziemlich kompliziert aus. Kannst Du nicht das ewig lange IF..THEN..ELSE irgendwie in logisch zusammenhängende von mir aus auch auf 2 oder 3 Case Blöcke verteilen ? Zur Fehlersuche möchte ich den Code nicht. :mrgreen:
WHERE A.[ist Kunde]
Vielleicht druck ich mirs mal aus und schau genauer. Aber erklär mir mal das mit den [] und das was da drin steht. Gruß Hansa |
Bei dieser Abfrage geht es um folgendes.
Ich habe in der Access-DB einige Tabellen. Ich habe hier eine Abfrage, die aus 2 Tabellen besteht.
Code:
Tabelle A = Kundendaten und Tabelle B = Geschäftsdaten.
cSql := 'Select DISTINCT A.KundenNr, A.Anrede, A.Titel, A.Vorname, A.Nachname, A.Straße, A.PLZ, A.Ort, A.Geburtsdatum, A.Land, A.Beruf, A.Telefon, A.Mobil, A.Fax, A.email FROM Kundendaten A LEFT JOIN Geschaeftsdaten B ON A.KundenNr = B.KundenNr ';
if (allekunden.Checked) and (flv.Checked) and (lv.Checked) and (df.Checked) and (ff.Checked) and (sv.Checked) and (bsp.Checked) and (sto.Checked) then cSql := cSql + ' AND ( [A.ist Kunde] = True OR [B.flv] = True OR [B.lv] = True OR [B.df] = True OR [B.ff] = True OR [B.sv] = True OR [B.bsp] = True OR [B.sto] = True OR [A.email] = True OR [B.eigengeschaeft] = True)'..... Das A weist auf eine Tabelle hin und [ist Kunde] = Feld in der Tabelle. Ich habe für diese Abfrage ca 4 Wochen mit hilfe eines Freundes gebraucht. Diese Funktioniert aber jetzt einwandfrei. |
Hallo m-werk,
was ich meinte ist, wenn du z.B. folgendes SQL Statement erzeugst:
Code:
dann (vorausgesetzt es gibt keine Kundenummer 0) sollte eine leere Datenmenge erzeugt werden, die die gewünschte Struktur hat. Wenn du diese dann (solange bis du eine echte Abfrage startest) im Grid anzeigst, sollte das Verschieben der Spalten und das Speichern in der Ini-Datei funktionieren.
Select DISTINCT A.KundenNr, A.Anrede, A.Titel, A.Vorname, A.Nachname, A.Straße, A.PLZ, A.Ort, A.Geburtsdatum, A.Land, A.Beruf, A.Telefon, A.Mobil, A.Fax, A.email FROM Kundendaten WHERE A.KundenNr = 0
|
Das speichern der Columns sollte auch mit
DBGrid1.Columns.SaveToFile('c:\sortierung.txt'); und DBGrid1.Columns.LoadFromFile('c:\sortierung.txt'); funktionieren :witch: |
Re: Spalten in einem DBGrid verschieben und auch sortieren!
Halo,
habe den Code zum einlesen der Spalten einmal ausprobiert. Leider werden die Spaltensortierung eingelesen, aber hat keine Auswirkung auf die Anzeige. Ich habe auch keine Möglichkeit gefunden die Anzeige zu refreshen. Der Tipp mit dem DBGrid1.Columns.SaveToFile('c:\sortierung.txt'); ist toll, und anschließend funktioniert auch die Anzeige. Ich möchte duiesen Inhalt aber in eine Ini-Datei ablegen. Hier verzweifel ich. Habe auch keine Ahnung, wie ich einen TStringStream direkt in eine INI-Section bekomme. mfg waldforest [delphi] procedure TQueryForm.GridToIni(GridName: TDBGrid; Section: string); var MS: TMemoryStream; Ini : TIniFile; tTv: TStringStream; node : string; n: integer; begin tTv := TStringStream.Create(''); MS := TMemoryStream.Create; Ini:=TIniFile.Create(ChangeFileExt(Application.Exe Name,'.ini')); try GridName.Columns.SaveToStream(MS); MS.Position := 0; tTv.Read(MS,ms.Size) ; INI.EraseSection(Section); INI.WriteString(Section, '', tTv.DataString); // Hier läuft die Anwendung auf Fehler finally tTv.Free; MS.Free; end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:41 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz