FastReport - dostęp do komponentu kbmmemtable

0

Przy bardziej skomplikowanych wydrukach czasem jest problem ze zliczaniem niektórych danych, dlatego zawsze muszę używać wiele zmiennych lub tablice.
Zamiast tego próbuję z poziomy wydruku obsługiwać komponent kbmmemtable (który jest na formie w Delphi).
Ten kbmmemtable jest widoczny jako źródło danych, mogę do niego podłączyć wstęgi, ale nie wiem jak go modyfikować (dodanie kolumn, Append, Delete, Update)

Próbuję tak:

var dataset : TDataSet;
begin
   dataset := TDataSet(Report.GetDataset('kbmMemTable'));
   dataset.FieldDefs.Add('Wiek',ftInteger,0,True);        <--- Acces Violation
end;

Czy to jest możliwe?

Albo
jak stworzyć wewnętrznego dataseta którego będę mogł modyfkować i który będzie widoczny jako źródło danych dla wstęgi?

1

wewnątrz kodu FR nie możesz zmieniać DS. Możesz to robić w delphi. Napisz może co chcesz osiągnąć

0

Robisz to zupełnie od tyłka strony. Dlaczego wydruk ma dodawać jakieś dane? Przy takich wydrukach najlepiej będzie jak w ramach formatki zrobisz sobie metodę np GetDataToReport() która to wypełni sobie komponent kbmMemTable danymi, a wydruk wydrukuje te dane.

0

ale na jednym oknie mam wiele różnych wydruków więc dane muszą być wypełnianie z poziomy wydruku.
Jedyne co wymyśliłem to dodanie do fastreporta kilku zewnętrznych funkcji które będą operować na tym kbmie typu dodaj pole, dodaj rekord edytuj itp

0

To w takim razie podziel te wydruki na oddzielne okna. Mieszanie kilku rzeczy nie jest najlepszym pomysłem. Już wolę nie zgadywać jak to się edytuje...

0
abrakadaber napisał(a):

wewnątrz kodu FR nie możesz zmieniać DS. Możesz to robić w delphi. Napisz może co chcesz osiągnąć

A niby dlaczego nie można?
Oczywiście, że można.
Mogę sobie równie dobrze takiego DSa w całości utworzyć w raporcie, wypełnić go danymi i zniszczyć.
A jak czegoś mi brakuje (w obszarze funkcjonalności FastScripta), to mogę sobie to dodać i zarejestrować FastScripta w raporcie.
Praktycznie wszystko jest możliwe...

0

próbowałem dynamicznie utworzyć dataseta na wydruku:

var DynamicznyDataset : TDataset;
begin
   DynamicznyDataset := TDataset.Create(nil);
   DynamicznyDataset.FieldDefs.Add('ID',ftInteger, 0, True);
   DynamicznyDataset.Open;                   
end;

ale na linii DynamicznyDataset.Open mam błąd Abstract Error.
A może robię to źle?

0

A ja się zastanawiam dlaczego chcesz tworzyć klasę bazową której duża ilość metod jest zadeklarowana jako virtual i de facto są to tylko stuby które nic nie robią. http://docwiki.embarcadero.com/Libraries/Berlin/en/Data.DB.TDataSet Co więcej trzeba było poszukać chociaż co oznacza błąd http://docwiki.embarcadero.com/Libraries/Berlin/en/System.SysUtils.EAbstractError

Do takich rzeczy jak chcesz nie wykorzystuje się TDataSet. Użyj chociaż TClientDataSet który można utworzyć, dodać definicję pól i ręcznie wypełnić danymi.

0

TClientDataSet można ręcznie wypełniać danymi jeśli zamiast Open użyje się CreateDataSet.
Tylko że w Fastreporcie (bo tego dotyczy ten temat) nie ma TClientDataSet.
Jest TfrxCustomDataset ale nie ma właściwości CreateDataSet;

0

napisz może co chcesz osiągnąć bo widzę, że kręcisz się w koło na jakimś własnym pomyśle

0

Przecież napisałem że z poziomu FastReporta chcę utworzyć komponent, dodawać do niego kolumny a później INSERT i UPDATE.
zaproponowałem dostęp do komponentu KBMMemTable który jest na formie lub dynamiczne utworzenie TDataset wewnątrz wydruku.

0

nie - napisałeś co się tobie wydaje, że musisz zrobić - ja pytam o cel takiej operacji.

0

Cel?
np zliczanie ilości wystąpień każdej pozycji z faktury (czyli z DetailData)
Na każdym OnBeforPrint wstęgi DetalData sprawdzam czy w datasecie jest już taka pozycja - jak jest to zwiększam ilość jak nie to dodaję nowy rekord.
Chyba że ktoś zaproponuje prostsze rozwiązanie?

0

co???? Czy przypadkiem jedna pozycja na fakturze nie może wystąpić tylko raz? Może pokaż przykładowy wydruk i wytłumacz jak idiocie (najlepiej z rysunkami :P) co chcesz policzyć . BTW takie rzeczy to się załatwia zapytaniem i/lub sumowaniem/grupowaniem.

0

ale jak drukujesz listę wszystkich faktur (100 stron), każda faktura ma jakieś swoje pozycje.
Niech ktoś spróbuje zrobić zliczenie ile razy wystąpiły poszczególne towary na całym wydruku (czyli na wszystkich fakturach).

0

no to chyba prościej i szybciej będzie to policzyć po stronie SQLa - SELECT towar, count(towar) ile FROM pozycje_faktur WHERE warunek_na_faktury_ktore_drukujesz

0

oczywiście że tak prościej, ale:

  1. nie wiem które faktury drukuje klient (musiałbym najpierw przelecieć po całym datasecie żeby zebrać id faktur)
  2. na samym wydruku są opcje które dodatkowo ukrywają niektóre wiersze (np towary których ilość na danej fakturze jest mniejsza niż 10)

Zrobiłem najpierw zliczanie wszystkich id faktur do zmiennej string.
potem podstawiłem tę listę do zapytania

 ... 
WHERE id_faktura in ( '  + lista_id + ') 

Dla małych ilości działa dobrze.
Ale jak drukuję faktury za dłuższy okres to dostałem błąd: Too many values (more than 1500) in member list.

Okazuje się że FIREBIRD, bo na tym działa baza, może mieć tylko 1500 parametrów w warunku IN.

0

Nie chcesz chyba powiedzieć, że user sobie wybiera z jakiejś listy 1500 faktur na zestawienie? Jeśli tak to radzę Ci zmień to, bo to brzmi jak wytwór pijanego programisty. Jeśli masz inaczej to przecież możesz zawrzeć dokładnie takie same warunki jak wybierając automatem faktury. Daty, wartości, czy nawet ilość mniejsza niż 10.

0

chodzi i o to, że użytkownik ma różne kryteria w selekcji po którym może wyszukać faktury (po datach, po kwotach, po nazwisku, po statusach: opłacone, nieopłacone, anulowane itp i jeszcze inne warunki).
I teraz mam te same wszystkie warunki przenosić na wydruk uwzględniając dodatkowo opcje które są w oknie dialogowym na wydruku?

1
Pele2 napisał(a):

I teraz mam te same wszystkie warunki przenosić na wydruk uwzględniając dodatkowo opcje które są w oknie dialogowym na wydruku?

Skoro już masz te dane, to możesz po prostu przekazać referencję do Fastreporta na DataSet zawierający dane wybrane przez użytkownika i wydrukować.
Po prostu.
Naprawdę nie widzę, gdzie jest problem...
Nie trzeba przenosić tych danych przez jakikolwiek MemTable - bo i po co?

0

Przecież mam dostęp do dataseta z nagłówkami dokumentów (MasterData jest z nim połączona).
Ale jak pisałem wcześniej jest problem jeśli dataset zawiera więcej niż 1500 rekordów.

0
Pele2 napisał(a):

Przecież mam dostęp do dataseta z nagłówkami dokumentów (MasterData jest z nim połączona).

To go użyj.

Pele2 napisał(a):

Ale jak pisałem wcześniej jest problem jeśli dataset zawiera więcej niż 1500 rekordów.

Niezupełnie; wcześniej pisałeś o limicie dla klauzuli WHERE i operatora IN z limitem 1500 elementów.
A to mnie zupełnie nie obchodzi, ponieważ nie o tym piszę.
Powtarzam; skoro masz przefiltrowane dane w datasecie, które sobie user wyklikał, to nie zbieraj IDków z tego Dsa i nie przekazuj go do zapytania przez IN, tylko po prostu użyj tego DSa w raporcie.
Doczytaj sobie jak dodać dynamicznie DataSet do raportu - to banalne, dwie linie kodu...

0
wloochacz napisał(a):

skoro masz przefiltrowane dane w datasecie, które sobie user wyklikał, to nie zbieraj IDków z tego Dsa i nie przekazuj go do zapytania przez IN, tylko po prostu użyj tego DSa w raporcie.

Ale jeśli dane nie są posortowane (a nie są) to automatyczne podsumowanie na wstęgach nie wyjdzie tak jak bym chciał.
Żeby zliczyć ilość wystąpienia każdego towaru, rekordy w datasecie muszą być posortowane.
Poza tym, skoro towary są na DetailData, to znaczy że ten dataset jest wielokrotnie zamykany i otwierany, więc muszę zbierać ilości do wewnętrznych zmiennych.
Sam Fastreport tego nie potrafi zliczyć.

0

to utwórz w bazie tabelę, do której będziesz przed wywołaniem raportu zapisywał id dokumentów wybranych do raportu oraz jakąś nazwę/id sesji/użytkownika, aby pobierać na raporcie tylko dokumenty wybrane przez danego użytkownika, a następnie wykorzystuj tą tabelę w zapytaniach, np. poprzez join. w ten sposób będziesz mógł na końcu robić podsumowania.

0

@Paweł Dmitruk kolega używa Firebirda. W tym celu fajnie można wykorzystać mechanizm Global Temporary Tables (GTT) wtedy nie trzeba zapisywać nazwy czy tam ID usera. Tylko załadować tam dane i korzystać jak z normalnej tabeli wykonując na nich kolejne zapytania.

0

wszyscy mnie tutaj przekonują żeby nie robić tak jak chciałem.
Ale w końcu zrobiłem dostęp do KBM z poziomu fastreporta.
Położony jest na DataModule, więc jest widoczny w każdym oknie, a następnie z poziomu wydruku dodaję do niego pola i obsługę dodawania, usuwania i edycji rekordów.
I bardzo mi to ułatwiło wiele skomplikowanych podsumowań na wydrukach.

0

Generalnie jest ok, chociaż nie do końca. Bo używasz zmiennych globalnych. Wydaje się, że takie projektowanie programów jest ok, ale wcześniej czy później zemści się.

0

Okno wydruku jest modalne, więc nie da się zrobić dwóch wydruków jednocześnie, więc nie powinno być problemów.
Już kilka razy wykorzystałem ten komponent i wszystkie wydruki działają pięknie.

0

Ale tu nie chodzi o modalność/niemodalność. Wprowadzanie zmiennych globalnych tylko dlatego, że wygodnie jest ich używać podczas design-time jest złe. Ja wiem, cała biblioteka VCL polega na tych zmiennych i to moim zdaniem jest jej poważny minus. Popatrz, że wszędzie (nawet na tym forum) odradza się używanie zmiennych globalnych. Wprowadzają one (czasem) niejawne zależności oraz przy bardziej skomplikowanych systemach mogą prowadzić do trudnych do wyłowienia błędów.

1 użytkowników online, w tym zalogowanych: 0, gości: 1