[Erl] fpspreadsheet - Sheets löschen und erzeugen

Rund um die LCL und andere Komponenten
Antworten
Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6208
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

[Erl] fpspreadsheet - Sheets löschen und erzeugen

Beitrag von af0815 »

Ich habe so wie es aussieht einen Denkfehler.

Ich möchte einfach x Worksheets in einem Workbook erzeugen und vorher alles löschen. Später soll dann das Workbook auch gespeichert werden.
Mein Ansatz, eine Workbooksource die mit allen verbunden ist. Wenn ich auf den Button drücke, dann soll alles (Memoryleakfrei) gelöscht werden und die neuen Sheets erzeugt werden. Aktuell ist das ein absolutes Minimalbeispiel.

Code: Alles auswählen

unit uSheets;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  fpspreadsheetctrls, fpspreadsheetgrid;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    BuCreateSheets: TButton;
    sWorkbookSource: TsWorkbookSource;
    sWorkbookTabControl: TsWorkbookTabControl;
    sWorksheetGrid: TsWorksheetGrid;
    procedure BuCreateSheetsClick(Sender: TObject);
  private
 
  public
 
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.BuCreateSheetsClick(Sender: TObject);
var
  i: Integer;
  strWsName: String;
begin
  // Clear all old sheets
  sWorkbookSource.Workbook.RemoveAllWorksheets;
  // Create 6 Sheets with different name
  for i:= 0 to 5 do begin
    strWsName := 'WS'+IntToStr(i+1);
    sWorkbookSource.Workbook.AddWorksheet(strWsName,False);
  end;
 
end;
 
end.
 


Ich ging davon aus, das ich mit Removeallworksheets ein leeres Workbook bekomme und dann darin die neuen Sheets erzeugen kann.

Erstens sehe ich das erste Sheet 2x, und beim 2ten versuch gibt ein DeadBeef :-) = Speicherzugriffsproblem.

Schalte ich alle Debuggingabfragen ein, so kracht es bei

Code: Alles auswählen

#0 UTF8TOUTF16(0xf0f0f0f0 <error: Cannot access memory at address 0xf0f0f0f0>, 0x2abfdf4 'WS1') at lazutf8.pas:3734
#1 UTF8COMPARETEXT(0xf0f0f0f0 <error: Cannot access memory at address 0xf0f0f0f0>, 0x2abf734 'WS1') at lazutf8.pas:3344
#2 TSWORKBOOK__GETWORKSHEETBYNAME(0x2abf734 'WS1', <error reading variable>) at .\common\fpspreadsheet.pas:8760
#3 TSWORKBOOK__VALIDWORKSHEETNAME(0x2abf734 'WS1', false, <error reading variable>) at .\common\fpspreadsheet.pas:8892
#4 TSWORKBOOK__ADDWORKSHEET(0x2abf734 'WS1', false, <error reading variable>) at .\common\fpspreadsheet.pas:8549
#5 TFORM1__BUCREATESHEETSCLICK(0x2c48868, <error reading variable>) at usheets.pas:46
#6 TCONTROL__CLICK(<error reading variable>) at .\include\control.inc:2850
#7 TBUTTONCONTROL__CLICK(<error reading variable>) at .\include\buttoncontrol.inc:55
#8 TCUSTOMBUTTON__CLICK(<error reading variable>) at .\include\buttons.inc:169
#9 TBUTTONCONTROL__WMDEFAULTCLICKED({MSG = 66567, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}, <error reading variable>) at .\include\buttoncontrol.inc:21
#10 SYSTEM$_$TOBJECT_$__$$_DISPATCH$formal at :0
#11 ?? at :0
#12 TWINCONTROL__WNDPROC({MSG = 66567, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}, <error reading variable>) at .\include\wincontrol.inc:5396
#13 DELIVERMESSAGE(0x2c48868, <error reading variable: Attempt to dereference a generic pointer.>) at lclmessageglue.pas:112
#14 TWINDOWPROCHELPER__DOWINDOWPROC(<error reading variable>) at .\win32\win32callback.inc:2496
#15 WINDOWPROC(134848, 273, 34920, 134856) at .\win32\win32callback.inc:2654
#16 CUSTOMFORMWNDPROC(134848, 273, 34920, 134856) at .\win32\win32wsforms.pp:386
#17 USER32!AddClipboardFormatListener at :0
#18 USER32!DispatchMessageW at :0
#19 USER32!SendMessageW at :0
#20 USER32!SendMessageW at :0
#21 CreateMappedBitmap at :0
#22 DetachScrollBars at :0
#23 USER32!AddClipboardFormatListener at :0
#24 USER32!DispatchMessageW at :0
#25 USER32!CallWindowProcW at :0
#26 CALLDEFAULTWINDOWPROC(134856, 514, 0, 983106) at .\win32\win32callback.inc:97
#27 TWINDOWPROCHELPER__DOWINDOWPROC(<error reading variable>) at .\win32\win32callback.inc:2404
#28 WINDOWPROC(134856, 514, 0, 983106) at .\win32\win32callback.inc:2654
#29 BUTTONWNDPROC(134856, 514, 0, 983106) at .\win32\win32wsstdctrls.pp:1603
#30 USER32!AddClipboardFormatListener at :0
#31 USER32!DispatchMessageW at :0
#32 USER32!DispatchMessageW at :0
#33 USER32!DispatchMessageW at :0
#34 TWIN32WIDGETSET__APPPROCESSMESSAGES(<error reading variable>) at .\win32\win32object.inc:407
#35 TAPPLICATION__HANDLEMESSAGE(<error reading variable>) at .\include\application.inc:1276
#36 TAPPLICATION__RUNLOOP(<error reading variable>) at .\include\application.inc:1413
#37 TWIDGETSET__APPRUN(0x425e50 <TAPPLICATION__RUNLOOP>, <error reading variable>) at .\include\interfacebase.inc:54
#38 TAPPLICATION__RUN(<error reading variable>) at .\include\application.inc:1401
#39 main at MoreSheets.lpr:19
 

SVN-r5919 mit Lazarus 1.8.0RC2 r55301 FPC 3.1.1 i386-win32-win32/win64

Irgendwie habe ich das Gefühl einen kapitalen Hirsch zu schiessen, aber die beiden Wiki's zu fpspreadsheet haben mich da auch nicht weitergebracht und bei dem Beispielen habe ich nicht verwertbares gefunden.

Andreas
Zuletzt geändert von af0815 am So 18. Jun 2017, 08:54, insgesamt 1-mal geändert.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6208
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: fpspreadsheet - Sheets löschen und erzeugen

Beitrag von af0815 »

Langsam wird es klar, das funktioniert

Code: Alles auswählen

procedure TForm1.BuCreateSheetsClick(Sender: TObject);
var
  i: Integer;
  strWsName: String;
begin
  // Clear all old sheets
  sWorkbookSource.CreateNewWorkbook;
  // Create 5 Sheets with different name
  for i:= 0 to 5 do begin
    strWsName := 'WS'+IntToStr(i+1);
    sWorkbookSource.Workbook.AddWorksheet(strWsName,False);
  end;
  // Now its safe to remove the unwanted sheet
  sWorkbookSource.Workbook.RemoveWorksheet(sWorkbookSource.Workbook.GetWorksheetByIndex(0));
end;
 

Nur das Problem das über den Workbooklink erzeugt wird, sollte entweder erkannt werden und einen vernünftigen Text bekommen zB. 'no valid worksheet' oder vermieden werden. Zumindest die Nachvollziehbarkeit ist ein Horror.

Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

wp_xyz
Beiträge: 4888
Registriert: Fr 8. Apr 2011, 09:01

Re: fpspreadsheet - Sheets löschen und erzeugen

Beitrag von wp_xyz »

Ich hätte es so gemacht (und so funktioniert es auch):

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
  strWsName: String;
  book: TsWorkbook;
begin
  book := TsWorkbook.Create;
  for i:=0 to 5 do begin
    strWsName := 'WS' + IntToStr(i+1);
    book.AddWorksheet(strWsName, false);
  end;
  sWorkbookSource.LoadFromWorkbook(book);
  // book nicht freigeben, da es im WorkbookSource weiterverwendet wird
end;

Aber eigentlich ist dein Code völlig in Ordnung. Wahrscheinlich ist das eine Folge der relativ undurchsichtigen Wechselwirkungen zwischen Workbook, WorkbookSource und visuellen Komponenten. Ich muss mir das bei Gelegenheit mal näher anschauen.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6208
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: fpspreadsheet - Sheets löschen und erzeugen

Beitrag von af0815 »

wp_xyz hat geschrieben:Aber eigentlich ist dein Code völlig in Ordnung. Wahrscheinlich ist das eine Folge der relativ undurchsichtigen Wechselwirkungen zwischen Workbook, WorkbookSource und visuellen Komponenten. Ich muss mir das bei Gelegenheit mal näher anschauen.

Es ist nicht so undurchsichtig. Das Problem ist, das zumindest ein WorkSheet da sein muss, da die Routinen ansonsten ungültige Zeiger verwenden. Frei nach dem Motto, es kann nicht sein, das es kein Worksheet gibt. So wird zum Beispiel versucht bei einem nicht vorhanden Worksheet zu erkennen ob der Name bereits vorhanden ist. Dabei wird versucht mit einem nicht gültigen Zeiger einen UTF8Stringvergleich durchzuführen, das kracht natürlich.
Ich habe in den Remarks dann gefundne das WorkBookLink Probleme hat, wenn kein Worksheet vorhanden ist, dann war ich auf der richtigen Fährte.

Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

wp_xyz
Beiträge: 4888
Registriert: Fr 8. Apr 2011, 09:01

Re: fpspreadsheet - Sheets löschen und erzeugen

Beitrag von wp_xyz »

Mit "undurchsichtig" meine ich, dass die visuellen Controls über Benachrichtigungen miteinander kommunizieren, und mir nicht immer 100% klar ist, welche Nachricht jetzt kommt - das war etwas zuviel Quick & Dirty.

Das Problem mit dem RemoveAllWorksheets war zum einen, dass zwar die Worksheets zerstört, aber nicht aus der Worksheet-Liste entfernt wurden, und zum anderen, dass das Workbook hier überhaupt keine Meldung an WorkbookSource gemacht hat. Den Controls den Boden unter den Füßen wegzuziehen, das geht natürlich schief.

Die neue Version sollte besser sein. Ich habe die Controls in der Komponentenpalette getestet, wie sie sich verhalten, wenn das Workbook RemoveallWorksheets aufruft und das Programm ohne aktives Worksheet bedient wird. Es gibt keinen Absturz mehr, wobei aber das eine oder andere Control, vor allem das Grid, noch etwas Feinschliff bräuchte. Die Actions habe ich nicht getestet - möglich, dass da noch die eine oder andere Überraschung lauert. Aber zuviel Arbeit möchte ich in diesen exotischen Fall auch nicht hineinstecken - die Leute werden sich schon melden.

Antworten