LINUXSOFT.cz Přeskoč levou lištu

ARCHIV



   

> Java (31) - základy tisku

Java U mnoha programů si nevystačíme jen s prohlížením dokumentu nebo nebo jiných dat na obrazovce. Potřebujeme to vytisknout. V Javě je to překvapivě jednoduché, tím spíš, že se stírají rozdíly mezi jednotlivými platformami, kde se jinak k tisku přistupuje dost odlišně.

16.1.2007 06:00 | Lukáš Jelínek | Články autora | přečteno 24260×

Základní pojmy

Než můžeme vůbec uvažovat o nějaké implementaci tisku, je potřeba dobře vědět, jak vůbec tiskový proces vypadá. A neuškodí si před tím připomenout některé pojmy, které se v této oblasti vyskytují.

Grafický kontext

Již jsme se s ním setkali, a to při kreslení. Reprezentuje ho třída Graphics a její potomci (typicky Graphics2D). Zjednodušeně řečeno, grafický kontext vyjadřuje, kam se kreslí. Pro kreslení na obrazovku se použije kontext spjatý s obrazovkou, pro tisk kontext tiskárny, mohou být i jiné kontexty (třeba pro nějaké operace v paměti).

Dokument

Dokument je to, co tiskneme. Data v něm obsažená se převádějí do tisknutelné podoby, do dat určených pro tiskárnu. Pod dokumentem si v této souvislosti můžeme představit cokoliv, třeba i nějakou komponentu GUI, pokud se nám zachce si ji vytisknout. Zde budeme k dokumentu přistupovat přes rozhraní Printable.

Stránka

Vcelku logická věc. Obvykle se tiskne na stránky, tedy listy papíru. Sice známe cosi jako "nekonečný papír", ale i tyto tiskárny, pokud netisknou pouze řádky textu, se stránkou jako plochou o určité velikosti pracují. Dokument se pro tisk děli právě na stránky, z nichž se tisknou třeba pouze některé. V Javě existuje rozhraní Pageable, představující sadu stránek, a dále třída PageFormat s popisem parametrů stránky.

Tisková úloha

Každý tisk má svůj začátek a konec. Například začneme první (nebo jinou) stránkou a skončíme poslední. Ať je to jakkoliv, jedná se o ohraničenou záležitost, které se říká tisková úloha. Lze si to představit třeba jako postscriptový soubor, který se sestaví, někam uloží a pak se pošle do tiskárny. Jak je to ve skutečnosti, je záležitost systému. V programu ovšem vidíme tak, že v podstatě vytvoříme ucelený balík dat a ať si s ním systém dělá, co chce. Pro úlohu slouží abstraktní třída PrinterJob.

Tisková služba

Tisková služba je v podstatě zobecněná virtuální tiskárna. Může to být místní tiskový démon, vzdálená tisková služba, ale třeba i jen nějaký program, který převádí data do určitého výstupního formátu. Tiskové služby teď necháme ještě spát, na ty přijde čas později. Zatím je důležité pouze to, že není-li k dispozici žádná tisková služba, nelze nic tisknout.

Tiskneme - nebo kreslíme?

Vrátíme-li se zpět do 25. dílu seriálu, kde se popisuje kreslení v metodě paint() grafických objektů, je tam zmínka též o metodách print() a printAll(). A také o tom, že by se na ně nemělo sahat. To je sice pravda, nicméně jsou případy, kdy to neplatí. Ale o tom až později. Nejdřív je důležité vědět, co se vůbec při tisku děje.

Každá komponenta obsahuje metody print() a printAll(). Jejich výchozí implementace jsou velmi jednoduché. Nastavují příznak tisku a chytají výjimky. Odlišně se chová pouze třída JTable, a to kvůli možnosti různě nakládat s dělením na stránky. Že jsou metody dvě, je pozůstatek z historie. Běžně se používá jen print().

Výše řečené znamená, že je tisk v podstatě ekvivalentní s běžným zobrazováním. Liší se jen v tom, že se pracuje s jiným grafickým kontextem. Pokud potřebujeme jiné chování, můžeme předefinovat print(), případně též další metody související s tiskem. Pokud jde o menší změny, stačí si jen někam poznamenat, že se tiskne (výše uvedený příznak není k dispozici - je deklarován jako private) a reagovat na to v paint().

Tiskový dokument

Nyní potřebujeme implementovat rozhraní Printable, které má jedinou metodu: print(Graphics, PageFormat, int). Jak je vidět z uvedeného prototypu, jako argumenty se předávají grafický kontext, formát stránky a její index. Metoda se stará o samotný tisk, přesněji řečeno vykreslení jedné stránky.

"Obyčejný" grafický kontext (třída Graphics) je navržen pro práci s celými čísly, v pixelech. Při tisku ovšem pixely nevidíme rádi, přirozenější jsou "klasické" měrné jednotky, tedy například tiskařský bod nebo centimetr. Proto musíme získat objekt třídy Graphics2D, který umožňuje takové jednotky (v plovoucí řádové čárce) používat.

Není pro to nutné udělat nic zvláštního, protože získaný grafický kontext je instancí právě této třídy, takže stačí přetypování. Navíc implementuje rozhraní PrinterGraphics, o kterém ještě bude řeč. Kontext můžeme používat obvyklým způsobem - tedy normálně kreslit dle libosti. Lze používat jak "celočíselné" metody (ze třídy Graphics), tak i metody přijímající parametry v plovoucí řádové čárce.

Transformace

Jistě se nyní můžeme ptát: jak vůbec zacházet s rozměry? Je to poměrně jednoduché. Grafický kontext obsahuje transformační matici o velikosti 3 x 3. Přes tuto matici se přepočítává vstupní prostor (ten, do kterého kreslíme) na výstupní (prostor zařízení). Matici můžeme měnit podle potřeby - pokud to neuděláme, použije se výchozí. Ta se získává z objektu grafické konfigurace (GraphicsConfiguration) příslušného zařízení, ale to není až tak důležité.

Mnohem větší význam má, jak ta matice vlastně vypadá. Máme tři případy:

  • zařízení s rozlišením blízkým 72 dpi (obrazovka) - používá se matice identity, tedy 1 jednotka odpovídá 1 pixelu.
  • zařízení s vysokým rozlišením (tiskárna) - používá se přepočet 72 jednotek na palec. Jinak řečeno, logická jednotka odpovídá tiskovému bodu.
  • kreslení do paměti - opět se 1 jednotka rovná 1 pixelu.

Výše popsané má samozřejmě hlubokou logiku, jak každý jistě pochopí. Pokud by to přesto někomu nevyhovovalo a chtěl by třeba místo tiskových bodů používat milimetry, cesta je snadná. Stačí prostě vytvořit novou matici (nebo lépe použít kopii té existující), příslušné koeficienty změnit a pak matici přiřadit grafickému kontextu. Ovšem pozor na to, že se s tím pak musí počítat úplně všude (třeba i u okrajů stránek)!

Nejjednodušší tisk

Dost bylo řečí, jdeme tisknout. Připomínám: implementujeme rozhraní Printable. Zde je krátký příklad:

public int print(Graphics g, PageFormat pageFmt, int index) {
  if (index != 0)
    return NO_SUCH_PAGE;
  
  Graphics2D g2 = (Graphics2D) g;
  
  g2.translate(pageFmt.getImageableX(), pageFmt.getImageableY());
  
  String s = "Tohle je text";
  TextLayout tl = new TextLayout(s, g2.getFont(), g2.getFontRenderContext());
  Rectangle2D rt = tl.getBounds();
  g2.drawString(s, 0, (float) rt.getHeight());
  
  return PAGE_EXISTS;
}

Vypadá to možná složitě, ale složité to není. První podmínka kontroluje, že jde o požadavek na tisk 1. stránky (pro ostatní vrátí, že stránka neexistuje). Pak následuje přetypování kontextu a jeho posun do oblasti tisku. Máme totiž definovány okraje a mimo ně tisknout nelze (nic by se tam nevytisklo). Posun lze samozřejmě pokaždé přičítat k souřadnicím, ale jednorázově je to lepší.

Další část se týká vykreslení textu. A tady pozor. Metoda drawString() totiž pracuje se svislou pozicí účaří, nikoli horní hranice oblasti textu. To je sice velmi důležité pro správné řádkování, působí to ovšem určité komplikace při správném umístění vzhledem k tisknutelné ploše. Proto musíme zjistit, kolik místa text ve svislém směru zabírá a podle toho ho umístit, aby nevyběhl za okraj.

Příklad pracuje s aktuálním písmem, tedy obvykle výchozím. Chceme-li jiné, musíme ho nastavit, a to samozřejmě ještě před výpočtem umístění. Obdobně, kdybychom třeba chtěli změnit barvu.

Tisk GUI

Již dříve jsem zmínil snadný tisk komponent GUI. Nyní uvedu příklad, jak by to mohlo vypadat:

JComponent c = ...

RepaintManager mgr = RepaintManager.currentManager(c);
boolean db = mgr.isDoubleBufferingEnabled();
mgr.setDoubleBufferingEnabled(false);
c.print(g2);
mgr.setDoubleBufferingEnabled(db);

Výše uvedený kód by nahradil odpovídající část v metodě print() z předchozího příkladu (tedy vše kromě záležitostí ohledně čísla stránky). Vlastní tisk spočívá pouze v zavolání metody print(). Vzhledem k výchozí transformační matici bude 1 pixel GUI odpovídat 1 tiskovému bodu.

Co stojí za zmínku, je dočasná deaktivace dvojitého bufferingu, pokud byl zapnutý. Při tisku je tato technika zbytečná (má za cíl zabránit blikání na obrazovce) a pokud by se použila, bude spotřebovávat paměť a čas procesoru.

Směr ... tiskárna

Zatím jsme ještě nic nevytiskli. Sice už víme, jak tisknout, ale ještě ne, jak vytvořit tiskovou úlohu a poslat ji na tiskárnu. Také tento úkol není vůbec těžký. Podívejme se na příklad:

protected void doPrint(Printable pt) {
  PrinterJob pj = PrinterJob.getPrinterJob();
  pj.setPrintable(pt);
  try {
    pj.print();
  } catch (PrinterException e) {
    JOptionPane.showMessageDialog(this,
        "Při tisku došlo k chybě: " + e.getMessage(),
        "Chyba", JOptionPane.ERROR_MESSAGE);
  }
}

Vše, co v tuto chvíli potřebujeme, je vytvořit tiskovou úlohu, předat jí dokument a spustit tisk. Tiskne se na výchozí tiskárnu s výchozími parametry (velikost stránky, okraje, rozlišení atd.). Všimněte si, že při tisku může nastat výjimka, která v příkladu způsobí zobrazení panelu s chybovou zprávou. Ještě připomenu již zmíněné rozhraní PrinterGraphics - přes něj se můžeme dostat k instanci tiskové úlohy (metodou getPrinterJob()).

Změna parametrů tisku

Někdy potřebujeme před tiskem změnit některé parametry - cílovou tiskárnu, formát stránky apod. Existují dva dialogy, které to umožňují. Prvním z nich je hlavní tiskový dialog, dostupný přes metodu printDialog(). Používá se například takto:

if (pj.printDialog())
  pj.print();

Dialog má dvě varianty, kromě výše uvedené (nativní) ještě přenositelnou, ke které se dostaneme příště. Pozor, metodu lze volat jen v případě, že máme možnost dialog zobrazit (jinak metoda vyhodí HeadlessException). Ke druhému dialogu, stránkovému, se dostaneme za chvíli.

Stránkovaný tisk

I když byl původní příklad navržen k tisku jen jediné stránky, klidně by jich mohl tisknout víc. Protože máme index stránky a její formát, není to problém. Jenže někdy to tak jednoduché není. Stránky v sadě mohou mít různý formát a pocházet z jiného logického dokumentu. Také předem neznáme celkový počet stránek k tisku.

Proto existuje rozhraní Pageable, které tyto problémy řeší. Má tři metody: getNumberOfPages(), vracející počet stránek, dále getPageFormat(), poskytující formát určité stránky, a konečně getPrintable(), zpřístupňující příslušný dokument ke stránce.

Teď jde o to, jak to použít. Buď si můžeme napsat vlastní implementaci, nebo použít tu, která už existuje. A to je třída Book. Má metody append() a setPage(), s jejichž pomocí lze snadno sestavit celou "knihu", tedy sadu stránek. Má-li to smysl, můžeme uživateli poskytnout možnost změnit formát stránky - jako jsme již použili metodu printDialog(), existuje podobná metoda pageDialog(). Poskytne se jí původní nastavení a získáme nové - tedy pokud uživatel provede změnu a potvrdí ji.

Objekt třídy Pageable máme, ale co s ním? Musíme ho nastavit tiskové úloze, a to metodou setPageable(). Úloha si "vytáhne" potřebné informace a použije je při tisku.

Jak získat náhled

Mnohdy se hodí mít možnost náhledu před tiskem. Ideální je generovat ho naprosto stejnou cestou jako samotný tisk. Vytvoříme si tedy nějakou komponentu (potomka JComponent), implementujeme metodu paint(), která bude obsahovat všechno potřebné ke kreslení. Bude-li se toto používat pro vícestránkový dokument, musí komponenta nějak rozlišit, které stránky se to týká (např. uložit si číslo aktuální stránky do nějaké proměnné).

Pak už stačí jen implementovat rozhraní Printable a v metodě print(Graphics, PageFormat, int) nejdřív nastavit aktuální číslo stránky a pak zavolat print(Graphics). Náhled se bude zobrazovat standardní cestou (jako normální grafická komponenta), jen je potřeba nějak zajistit výběr aktuální stránky (třeba tlačítky na panelu).

Ještě je tu jeden faktor, který má vliv na tisk i náhled: formát stránky, tedy instance PageFormat. Je potřeba, aby komponenta znala tento formát předem, aby se mohl použít už při náhledu.

Tiskové služby

Poslední oblastí v problematice tisku jsou tiskové služby. Je to záležitost poměrně rozsáhlá, proto jí bude věnován celý příští díl. Využití tiskových služeb umožňuje postoupit o úroveň výše a nemuset se tedy zabývat tím, kterou dostupnou tiskárnu použít k tisku požadovaného dokumentu. Vrstva tiskových služeb to totiž umí vyřešit za nás. A zvládá i mnohé další věci.

Ještě jedno doporučení na závěr. Budete-li experimentovat s tiskem, můžete používat pseudotiskárnu s výstupem do souboru (PostScript nebo PDF). Výsledek uvidíte hned a nemusíte plýtvat papírem.

Verze pro tisk

pridej.cz

 

DISKUZE

pokracovanie 13.3.2007 11:18 jano fero
Tisk jTextArea 19.5.2010 20:17 Roman Čižinský




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

28.11.2018 23:56 /František Kučera
Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1

12.11.2018 21:28 /Redakce Linuxsoft.cz
22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář

6.11.2018 2:04 /František Kučera
Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

4.10.2018 21:30 /Ondřej Čečák
LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář

18.9.2018 23:30 /František Kučera
Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

9.9.2018 14:15 /Redakce Linuxsoft.cz
20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business. Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář

12.8.2018 16:58 /František Kučera
Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář

16.7.2018 1:05 /František Kučera
Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

31.7.2023 14:13 / Linda Graham
iPhone Services

30.11.2022 9:32 / Kyle McDermott
Hosting download unavailable

13.12.2018 10:57 / Jan Mareš
Re: zavináč

2.12.2018 23:56 / František Kučera
Sraz

5.10.2018 17:12 / Jakub Kuljovsky
Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2024) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze