Pokazywanie postów oznaczonych etykietą drukowanie qt4. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą drukowanie qt4. Pokaż wszystkie posty

sobota, 24 listopada 2012

Drukowanie rozbudowanej tabeli w Qt4

Tydzień temu pisałem o drukowaniu dokumentów w Pythonie stosując metody biblioteki Qt4. Wszystko w kontekście tworzenia Kart Ewidencji Zabytków Archeologicznych (KEZA), które wypełnia się przede wszystkim na okoliczność prowadzenia badań w ramach projektu Archeologicznego Zdjęcia Polski.
Przypatrując się wzorcowej karcie KEZA można zauważyć, że faktycznie jest to bardzo rozbudowana tabela ze scalonymi komórkami. Eksperyment przeprowadzony przy pomocy Excela wykazał, że podobny efekt można osiągnąć stosując tabelę z 60 kolumnami i 35 wierszami równej wysokości, która wypełnia arkusz A4.

 Wstawianie tabeli

To okazało się szczęśliwym zrządzeniem losu, ponieważ dzięki temu i wykorzystaniu klas QTextDocument i QTextCursor nie musiałem implementować własnoręcznie funkcji rysującej tabelę. Zamiast tego mogłem wykorzystać metodę insertTable(wiersze, kolumny, format) klasy QTextCursor. Znaczenie dwóch pierwszych parametrów powinno być oczywiste. W pierwszym podaje się liczbę wierszy, w drugim liczbę kolumn. W przypadku tworzenia karty KEZA istotny jest trzeci, za pomocą którego określa się właściwości tabeli, takie jak obramowanie (border-style), odległość między obramowaniem a zawartością komórki (cellpadding). Te i inne parametry określa się w obiekcie klasy QTextTableFormat, podawanym jako trzeci argument metody insertTable. Po wykonaniu zwraca ona obiekt klasy QTextTable.

Przykład

Kod programu Pythona rozpoczynając od inicjalizacji klasy QTextDocument do wstawienia nowej tabeli mógłby wyglądać następująco:

doc = QTextDocument()
cur = QTextCursor(doc)
fmt = QTextTableFormat()
fmt.setCellPadding(1)
fmt.setBorderStyle(QTextFrameFormat.BorderStyle_Solid)
keza = cur.insertTable(35,60,fmt)

W sześciu liniach została utworzona duża tabela, zawierająca ponad 2100 komórek. Teraz kwestią pozostaje ich scalenia w taki sposób, żeby po wszystkim przypominała wzór karty KEZA. Do połączenia grupy komórek można zastosować metodę mergeCells(y, x, wysokosc, szerokosc) klasy QTextTable, gdzie argumenty y oraz x  oznaczają lokalizację pierwszej komórki w grupie łączonych (licząc od lewego górnego narożnika), a wysokość i szerokość to odpowiednio liczba komórek w pionie i w poziomie, które mają być scalone. Chcąc połączyć 6 komórek w górnym lewym rogu tabeli o wymiarach 3 x 2 trzeba wykonać polecenie keza.mergeCells(0,0,2,3). W przypadku generowania karty KEZA takich operacji jest zbyt dużo, aby każdą z osobna zapisywać jako wywołanie powyższej funkcji, dlatego zamiast tego stosuję prosty schemat w postaci pliku CSV, który zawiera definicję każdej docelowej komórki.

Formatowanie komórek

Na koniec pozostaje problem, jak odwołać się do wybranej komórki i wstawić do niej zawartość. Za pomocą metody cellAt(y,x) klasy QTextTable uzyskuje się referencję do komórki o podanych współrzędnych, którą reprezentuje klasa QTextTableCell. Metodą firstCursorPosition() można ustawić w niej kursor (dla przypomnienia reprezentuje go klasa QTextCursor) a następnie użyć go do wstawienia np. tekstu przy pomocy insertText(tekst). To nie wszystko każdą z komórek można formatować. Do tego potrzeba uzyskać informacje o jej bieżącym wyglądzie przy pomocy metody format() klasy QTextTableCell, a następnie stosując odpowiednie metody zmienić formatowanie. Na przykład metoda setBackground(Qt.yellow) zmieni tło komórki z białego na żółty. Na koniec należy to formatowanie jawnie zaplikować do komórki wywołując metodę setFormat. Bez tego zmiana tła będzie bezskuteczna.

Kontynuacja przykładu

keza.mergeCells(0,0,2,3)
grupa = keza.cellAt(0,0) # pobiera scaloną przed chwilą grupę komórek
gf = grupa.format() # formatowanie komórek
gf.setFont(QFont('Times',8,QFont.DemiBold))
grupa.setFormat(gf) # jawne wprowadzenie formatowania
grupa.firstCursorPosition().insertText('QAZP2') # zawartość komórki

drukarka = QPrinter()
doc.print_(drukarka) # wydrukowanie dokumentu na urządzeniu.

niedziela, 18 listopada 2012

Programowanie w Qt4: drukowanie tabel

Obecnie na "tapecie" mam problem generowania Kart Ewidencji Zabytków Archeologicznych (w skrócie KEZA), która jest formą archiwizowania informacji pochodzących z badań archeologicznych. Jej koncepcja wiąże się z początkami programu Archeologicznego Zdjęcia Polski, którego celem jest inwentaryzacja śladów osadnictwa w celu zapewnienia im ochrony konserwatorskiej. Jej wzór zmieniał się z biegiem lat, przy czym najważniejszym założeniem było to, by wszystkie informacje mieściły się na jednej kartce A4, co miało uzasadnienie w czasach "analogowych" metod archwizowania danych (to znaczy polegających na maszynowym wypełnianiu kart i wkładaniu do teczek czy segregatorów). Ponieważ do sprawozdania z badań archeologicznych muszą zawsze być dostarczone wydrukowane karty KEZA, to oczywiste jest, że QAZP2 musi także udostępniać taką funkcjonalność.
W najprostszej postaci wszystko czego potrzebujemy do drukowania przy pomocy Qt4 to dwie klasy: QPainter oraz QPrinter. Przykład ich zastosowania może wyglądać następująco:
drukarka = QPrinter()
drukarka.setOutputFormat(QPrinter.PdfFormat) # rodzaj drukarki
drukarka.setOutputFileName("nowy_plik.pdf")
painter = QPainter()
painter.begin(drukarka)
painter.drawText(10, 10, 'Test') # wydrukowanie tekstu
drukarka.newPage() # wysuniecie pierwszej strony
painter.drawText(10, 10, 'Test 2') # tekst na drugiej stronie
painter.end()

W w takiej formie drukowanie nie wiąże się z żadną filozofią: klasa QPrinter reprezentuje uniwersalny interfejs urządzenia, który umożliwia drukowanie do pliku PDF, na kartkach papieru i inne. Z kolei QPainter wykorzystując ten kanał wspomaga programistę w pisaniu na "urządzeniu" tekstu, rysowaniu figur geometrycznych albo drukowaniu obrazków.
Ponieważ karta KEZA to faktycznie tabela, to powższy kod byłby znacząco bardziej skomplikowany i zwiększający prawodopodobnieństwo wystąpienia błędów. Aby procedura drukowania była trochę bardziej abstrakcyjna, to QAZP2 zamiast klasy QPainter została wykorzystana inna - QTextDocument, która jak sama nazwa wskazuje jest używana do reprezentowania dokumentów. Te mogą być tworzone przez użytkownika, który wpisuje zdania w polu tekstowym, albo automatycznie przy pomocy klasy QTextCursor, która służy do określania miejsca, w którym bieżący dokument jest edytowany i wstawiania do niego różnych obiektów - ciągów znaków, tabel, obrazków, których kształ można określać za pomocą znaczników HTML. Gdy dokument jest już gotowy wystarczy wywołać funkcję print_(drukarka) klasy QTextDocument do wysłania go na urządzenie wskazane w parametrze drukarka. W tej metodzie zawartość dokumentu jest tłumaczona na ciąg poleceń takich jak w przykładzie powyżej.
To podejście w odróżnieniu od "niskopoziomowego" ma tą zaletę, że pozwala się skupić na zawartości dokumentu i jego wyglądzie. To w jaki sposób zostanie ona przełożona na papier albo plik PDF pozostaje w gestii klasy QTextDocument. Jak zostało ono wykorzystane w przypadku generowania karty KEZA opiszę następnym razem.