Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Dynamische Pages (TAdvOfficePage bzw. TAdvOfficePager)
LittleBen - Fr 22.04.11 19:41
Titel: Dynamische Pages (TAdvOfficePage bzw. TAdvOfficePager)
Hallo,
habe mal wieder ein kleines Problemchen. Es geht um das erzeugen, aber viel wichtiger, um das löschen von Pages auf einem Pager. Dazu verwende ich Komponenten der TMS-Bibliothek(TAdvOfficePage bzw. TAdvOfficePager).
Eine Page zu erzeugen ist kein Problem, doch eine zu löschen schon...
Der Vorgang:
Ich habe eine Procedure die
RefreshTab heißt. Diese löscht zuerst alle Tabs(auser den Ersten), und erzeugt dann wieder so viele Tabs, wie die StringList Items hat. Doch wenn ich mich gerade in einem Tab(nicht im Ersten) aufhalte und dann diese Procedure aufrufe, dann tritt ein Fehler(meist Zugriffsverletzung) auf. Doch das komische ist, dass dieser Fehler nur manchmal auftritt, auch wenn ich immer das selbe mache.
Wenn ich mich im ersten Tab aufhalte funktioniert alles.
Schaut es euch einfach mal an:
Delphi-Quelltext
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:
| procedure TF_Essen.RefreshTab; var aPage: TAdvOfficePage; aButton: TButton; i: integer; sl: TStringlist; begin sl:= TStringlist.Create; for i:= oReg1.AdvPageCount-1 downto 1 do begin oReg1.AdvPages[i].free; end; sl.Add('TEST'+inttostr(1)); sl.Add('TEST'+inttostr(2)); sl.Add('TEST'+inttostr(3)); sl.Add('TEST'+inttostr(4)); sl.Add('TEST'+inttostr(5)); for i:= 0 to sl.count-1 do begin aPage:= TAdvOfficePage.Create(self); aPage.AdvOfficePager:= oReg1; aPage.Caption:= sl.Strings[i]; aPage.Name:= 'Page'+inttostr(i+2); aPage.Tag:= i+2; aButton:= TButton.Create(Self); aButton.Parent:= oReg1.AdvPages[oReg1.AdvPageCount-1]; aButton.Caption:= 'Refresh '+IntToStr(i+1); aButton.Name:= 'b_refresh'+IntToStr(i+2); aButton.SetBounds(100,12+i*(aButton.Height+4),aButton.Width,aButton.Height); aButton.Tag:=i+2; aButton.OnClick:= b_refresh1Click; end; sl.Free; end; |
Habe mich dann ein bisschen schöau gemacht und den Tipp gelesen, dass man mit die Pages mit
Postmessage freigeben soll.
Also habe ich das getan. Hat sich dadurch auch deutlich verbessert!!
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| const PM_FREEPAGE = CM_Base+1; ... procedure TF_Essen.RefreshTab; var ... begin ... for i:= oReg1.AdvPageCount-1 downto 1 do begin PostMessage(Handle,PM_FREEPAGE,i,0); Application.ProcessMessages; end; ... end; |
Delphi-Quelltext
1: 2: 3: 4:
| procedure TF_Essen.PMFREEPAGE(var Message: TMessage); begin oReg1.AdvPages[Message.WParam].Free; end; |
Nun kommen nur abwechselnd irgendwelche Exceptions, etc...
Doch ich mach immer genau das Selbe:
Wechseln zu Page3-->Button drücken-->Wechseln zu Page3-->Button drücken-->Wechseln zu Page3-->Button drücken-->...
Und irgendwann kommt dann mal ein Fehler!
Warum?
Ich hoffe, dass ich mein Problem gut genug geschildert habe, sodass ihr mir auch helfen könnt :)
Freu mich schon auf eure Ideen!
Danke&Grüße
Benny
jaenicke - Fr 22.04.11 20:40
Ich kenne die Komponente eigentlich nicht, habe sie aber einmal kurz installiert. Da fällt mir sofort RemoveAdvPage beim Pager ins Auge. Hast du das einmal damit versucht statt die Seite einfach freizugeben?
Bei mir funktioniert das damit problemlos, ohne irgendwelche Messages oder irgendetwas Besonderes. :nixweiss:
LittleBen - Fr 22.04.11 21:44
Also wenn ich es so mache:
Delphi-Quelltext
1: 2:
| for i:= 2 to oReg1.AdvPageCount do oReg1.RemoveAdvPage(TAdvOfficePage(FindComponent('Page'+inttostr(i)))); |
und dann wieder meine Pages erstelle, kommt sofort der Fehler, dass
Page2 schon vorhanden ist.
Ich denke dass
RemoveAdvPage die Page nicht wirklich Destroyed.
Grüße
Benny
jaenicke - Fr 22.04.11 21:47
Na gut, das hatte ich jetzt natürlich nicht getestet. Und wie sieht es mit einer Kombination aus beidem aus? Erst entfernen, dann freigeben? :zwinker:
LittleBen - Fr 22.04.11 21:52
Das funktioniert dann, wenn ich mich im ersten Tab aufhalte.
Wenn nicht, dass gibt es wieder, aber nur Manchmal, eine Zugriffsverletzung...
Delphi-Quelltext
1: 2: 3: 4: 5:
| for i:= oReg1.AdvPageCount-1 downto 1 do begin oReg1.RemoveAdvPage(TAdvOfficePage(FindComponent('Page'+inttostr(i+1)))); TAdvOfficePage(FindComponent('Page'+inttostr(i+1))).Free; end; |
Als ich nach dem Problem gegooglet hatte, bin ich ja auf den Tipp mit
Postmessage gekommen.
Hier die Erklärung dafür:
Zitat: |
PostMessage wird hier verwendet, weil PostMessage ans Ende der Botschafts-
warteschlange gestellt wird und deshalb erst abgearbeitet wird wenn alle
anderen Botschaft, wie z.B. die Click Botschaft an den Button abgearbeitet
wurde |
EDIT: Zurzeit kommen auch Fehlermeldungen wie "Priviligierte Anweisung" oder "Abstrakter Fehler"
jaenicke - Fr 22.04.11 22:25
Ja, wenn du auch die Seite freigeben willst, auf der der Button ist, so dass der mit freigegeben wird... :shock:
Dann musst du das eben alles kombinieren, Message schicken, dort Seiten entfernen und freigeben.
LittleBen - Fr 22.04.11 22:27
Wie meinen?
Edit: Also meinst du, dass ich den Button auch(manuell) freigeben muss?
jaenicke - Fr 22.04.11 22:48
Ok, ich habe es ausprobiert. Und dabei dann ClearAdvPages gesehen. So klappt es bei mir absolut problemlos:
Delphi-Quelltext
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:
| const WM_TEST = WM_USER + 3290;
type TForm746 = class(TForm) TestPager: TAdvOfficePager; procedure FormCreate(Sender: TObject); private procedure RecreatePagesClick(Sender: TObject); protected procedure WmTest(var Msg: TMessage); message WM_TEST; public end;
var Form746: TForm746;
implementation
{$R *.dfm}
procedure TForm746.RecreatePagesClick(Sender: TObject); begin PostMessage(Handle, WM_TEST, 0, 0); end;
procedure TForm746.FormCreate(Sender: TObject); begin RecreatePagesClick(Sender); end;
procedure TForm746.WmTest(var Msg: TMessage); var i: Integer; NewPage: TAdvOfficePage; NewButton: TButton; begin TestPager.ClearAdvPages;
for i := 0 to Random(10) + 1 do begin NewPage := TAdvOfficePage.Create(Self); NewPage.AdvOfficePager := TestPager; NewPage.Caption := 'Page ' + IntToStr(i); NewPage.Name := 'Page' + IntToStr(i);
NewButton := TButton.Create(Self); NewButton.Parent := NewPage; NewButton.Caption := 'Refresh ' + inttostr(i + 1); NewButton.Name := 'b_refresh' + inttostr(i + 2); NewButton.SetBounds(100, 12 + i * (NewButton.Height + 4), NewButton.Width, NewButton.Height); NewButton.Tag := i + 2; NewButton.OnClick := RecreatePagesClick; end; end; |
LittleBen - Fr 22.04.11 22:56
Vielen,vielen Dank!
Vorallem dass du dir die Mühe gemacht hast!
Doch ich musste erschreckend feststellen, dass ich diese Funktion nicht habe :(
Könntest du sie vielleicht posten?
Vielen Danke!
jaenicke - Fr 22.04.11 23:07
Ich habe nur die Trial, also keine Quelltexte. ;-)
Aber dann eben ohne diese Funktion, so funktioniert es ebenfalls problemlos:
Delphi-Quelltext
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:
| uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, AdvOfficePager, StdCtrls, Generics.Collections;
const WM_TEST = WM_USER + 3290;
type TForm746 = class(TForm) TestPager: TAdvOfficePager; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private FPageList: TObjectList<TAdvOfficePage>; procedure RecreatePagesClick(Sender: TObject); protected procedure WmTest(var Msg: TMessage); message WM_TEST; public end;
var Form746: TForm746;
implementation
{$R *.dfm}
procedure TForm746.FormDestroy(Sender: TObject); begin FPageList.Free; end;
procedure TForm746.RecreatePagesClick(Sender: TObject); begin PostMessage(Handle, WM_TEST, 0, 0); end;
procedure TForm746.FormCreate(Sender: TObject); begin FPageList := TObjectList<TAdvOfficePage>.Create(True); RecreatePagesClick(Sender); end;
procedure TForm746.WmTest(var Msg: TMessage); var i: Integer; NewPage, CurrentPage: TAdvOfficePage; NewButton: TButton; begin for CurrentPage in FPageList do TestPager.RemoveAdvPage(CurrentPage); FPageList.Clear;
for i := 0 to Random(10) do begin NewPage := TAdvOfficePage.Create(nil); NewPage.AdvOfficePager := TestPager; NewPage.Caption := 'Page ' + IntToStr(i); NewPage.Name := 'Page' + IntToStr(i); FPageList.Add(NewPage);
NewButton := TButton.Create(Self); NewButton.Parent := NewPage; NewButton.Caption := 'Refresh ' + inttostr(i + 1); NewButton.Name := 'b_refresh' + inttostr(i + 2); NewButton.SetBounds(100, 12 + i * (NewButton.Height + 4), NewButton.Width, NewButton.Height); NewButton.Tag := i + 2; NewButton.OnClick := RecreatePagesClick; end; end; |
// EDIT:
Ich sehe gerade, dass du nur Delphi 5 und 7 hast? Dann musst du eine normale TObjectList nehmen und statt for..in eine normale for-Schleife. ;-)
LittleBen - Fr 22.04.11 23:18
Genau, habe nur Delphi 5 und 7. Wie meinst du das mit der for-schleife? Bekomme ich irgendwie nicht hin :(
Trotzdem nochmal viiiiielen Dank :)
jaenicke - Fr 22.04.11 23:33
Naja, so halt:
Delphi-Quelltext
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:
| uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, AdvOfficePager, StdCtrls, Contnrs;
const WM_TEST = WM_USER + 3290;
type TForm746 = class(TForm) TestPager: TAdvOfficePager; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private FPageList: TObjectList; procedure RecreatePagesClick(Sender: TObject); protected procedure WmTest(var Msg: TMessage); message WM_TEST; public end;
var Form746: TForm746;
implementation
{$R *.dfm}
procedure TForm746.FormDestroy(Sender: TObject); begin FPageList.Free; end;
procedure TForm746.RecreatePagesClick(Sender: TObject); begin PostMessage(Handle, WM_TEST, 0, 0); end;
procedure TForm746.FormCreate(Sender: TObject); begin FPageList := TObjectList.Create(True); RecreatePagesClick(Sender); end;
procedure TForm746.WmTest(var Msg: TMessage); var i: Integer; NewPage: TAdvOfficePage; NewButton: TButton; begin for i := 0 to FPageList.Count - 1 do TestPager.RemoveAdvPage(FPageList[i] as TAdvOfficePage); FPageList.Clear;
for i := 0 to Random(10) do begin NewPage := TAdvOfficePage.Create(nil); NewPage.AdvOfficePager := TestPager; NewPage.Caption := 'Page ' + IntToStr(i); NewPage.Name := 'Page' + IntToStr(i); FPageList.Add(NewPage);
NewButton := TButton.Create(Self); NewButton.Parent := NewPage; NewButton.Caption := 'Refresh ' + inttostr(i + 1); NewButton.Name := 'b_refresh' + inttostr(i + 2); NewButton.SetBounds(100, 12 + i * (NewButton.Height + 4), NewButton.Width, NewButton.Height); NewButton.Tag := i + 2; NewButton.OnClick := RecreatePagesClick; end; end; |
LittleBen - Fr 22.04.11 23:39
ES FUNKTIONIERT!!
Vielen Dank für alles!!!!
Bin nun so erlöst :)
Nochmals Danke und eine gute Nacht!
Grüße,
Benny
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!