Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 14 of 14

Thread: Trying to figure out how to print multiple things on same page

  1. #1
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    432
    My Mood
    Depressed
    Thanks
    54
    Thanked 67 Times in 67 Posts

    Unhappy Trying to figure out how to print multiple things on same page

    Ok, I heard that java doesn't really have any easy way to get it to say, call print on a JTable and a JTextArea and, even if there IS room, to put them on the same page. It always seems to go to a new page for each item, or so I've read that it will. I've found out a nice tutorial that shows me MOST of what I can do to get around this, it involved something called a BufferedImage, but they have something in there that can't compile and will throw a NullPointerException the only way I can think of it to run it.

    I'm not sure how to DIRECTLY call the print method of a Printable subclass. I cannot get a Graphics object to go and getGraphics() is returning null.

    I thought it would be PrinterJob, but that doesn't seem to be what they're hinting at. However, they kinda said that PrinterJob normally always will print it on two separate pages for each item. I DON'T want that.

    I have tried to find a way to call the Printable.print() directly online, but it always keep suggesting that I use PrinterJob. I cannot deduce what the guy meant as he left no examples (nor was I the only one confused from the looks of the comments on the page.)

    Here's his tutorial:
    Hot Coding!: Printing multiple Printables in Java

    He suggests this at the end for how to work it:

    For each Printable, JTable.getPrintable(...), wrap it with MyPrintable object and then print the wrapper.


    MyPrintable prt = new MyPrintable(table.getPrintable(...))
    ...
    while (prt.print(graphics,pf,pageIndex) == PAGE_EXISTS){
    if (prt.getSpaceLeft() < 100){
    // create a new page or a new graphics
    // reset page index to 0
    }
    pageIndex++;
    }
    // looping to the next Printable...

    First off, table.getPrintable() isn't a no argument method. (However, I figured that out and got that to compile.)

    However, I have no clue what he wanted me to do with his

    ......

    The line: while (prt.print(graphics,pf,pageIndex) == PAGE_EXISTS)

    Doesn't seem to work. He doesn't put the stuff in a method that is passed a Graphics object. I cannot get a Graphics object and getGraphics() is returning null so that can't be the way to do it.

    I keep being told online that I should use a PrinterJob object. However, that returns void. His example seems to require an int.

    The print method of Printable DOES return an int, but there is the issue of passing it a Graphics object that works.

    Here is what my attempt at trying to get it to work. It will compile but will throw a NullPointerException because getGraphics() is null.


        /*
        * To change this template, choose Tools | Templates
        * and open the template in the editor.
        */
        package printer;
     
        import java.awt.Graphics;
        import java.awt.Graphics2D;
        import java.awt.image.BufferedImage;
        import java.awt.image.DataBufferInt;
        import java.awt.print.PageFormat;
        import java.awt.print.Paper;
        import java.awt.print.Printable;
        import java.awt.print.PrinterException;
     
        /**
        *
        * @author pballeux
        */
        public class MyPrintable implements Printable {
     
        Printable delegate;
        double spaceLeft = 0;
        double minimumRequired = 72;
        static int debugindex = 0;
     
        public MyPrintable(Printable p) {
        this.delegate = p;
        }
     
        public MyPrintable(Printable p, double minimumHeight) {
        this.delegate = p;
        this.minimumRequired = minimumHeight;
        }
     
        public void setMinimumRequired(double height) {
        minimumRequired = height;
        }
     
        public double getMinimumRequired() {
        return minimumRequired;
        }
     
     
        public double getSpaceLeft() {
        return spaceLeft;
        }
     
        private int detectLastLine(BufferedImage img) {
        int lastIndex = 0;
        int[] data = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
        for (int i = data.length - 1; i > 0; i--) {
        if (data[i] != 0) {
        lastIndex = i;
        break;
        }
        }
        return (lastIndex / img.getWidth());
        }
     
        @Override
        public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
        BufferedImage img = new BufferedImage((int) pageFormat.getWidth(), (int) pageFormat.getHeight(), BufferedImage.TRANSLUCENT);
        Graphics2D g = img.createGraphics();
        int retValue = delegate.print(g, pageFormat, pageIndex);
        if (retValue == PAGE_EXISTS) {
        //Find out bound of printing...
        //System.out.println("Last Line drawn is : " + detectLastLine(img));
        // try {
        // ImageIO.write(img, "jpg", new File("img" + debugindex++ + ".jpg"));
        // } catch (IOException ex) {
        // }
        spaceLeft = (pageFormat.getImageableY() + pageFormat.getImageableHeight()) - detectLastLine(img);
        retValue = delegate.print(graphics, pageFormat, pageIndex);
        //Updating paper after the hardprint
        Paper paper = pageFormat.getPaper();
        paper.setImageableArea(paper.getImageableX(), paper.getImageableY() + paper.getImageableHeight() - spaceLeft, paper.getImageableWidth(), spaceLeft);
        pageFormat.setPaper(paper);
        }
        return retValue;
        }
     
     
     
     
    // For each Printable, JTable.getPrintable(...), wrap it with MyPrintable object and then print the wrapper.
     
     
      public static void main(String[] args)
      {
     
     
       Object[][] rows = new Object[2][2];
     
       for (int i =0; i < rows.length; i++)
       {
     
       for (int j=0; j < rows[i].length; j++)
       {
       rows[i][j] = i*j;
     
       }
     
       }
     
       Object[] data = new Object[2];
     
       data[0] = "Mike";
       data[1] = "Bob";
     
       javax.swing.JTable table = new javax.swing.JTable(rows, data);
     
        MyPrintable prt = new MyPrintable(table.getPrintable(javax.swing.JTable.PrintMode.NORMAL, null, null));
        int pageIndex = 0;
     
        try
        {
        while (prt.print(table.getGraphics(), new java.awt.print.PageFormat(),pageIndex) == PAGE_EXISTS){
        if (prt.getSpaceLeft() < 100){
        // create a new page or a new graphics
        // reset page index to 0
        }
        pageIndex++;
        }
        // looping to the next Printable...
        }
     
        catch(PrinterException pe)
        {
     
     
        }
     
     
     
     
    }

    I cannot figure out what he meant when he called the print() method from Printable directly.

    There is nothing online that mentions what to do.

    Note, I tried using PrinterJob with the MyPrintable object and that printed it out on TWO pages. That is NOT what I want.

    I have just found that the guy who did the tutorial has a Google plus page. (I found that in the comments that it went there. So I've contacted him as well.


    However, if you can tell me what he might have meant, that would be great.

    (Originally, when I made this topic, I didn't see that the comments were through Google Pus and the guy hadn't responded on the tutorial page to a comment somebody else made asking for an example of how to use his class and what he meant. Someone made that comment 6 months ago and it still hasn't gotten a reply on the tutorial page. So, I thought I'd go here.

    I was going back to the page to see, yet again, if I'd missed something in what he said. That's when I found a way to contact him on his Google Plus Account (which he last used three days ago).
    Last edited by GoodbyeWorld; June 8th, 2014 at 06:09 PM. Reason: Found a way to contact guy who made tutorial
    JavaScript is NOT Java.


  2. #2
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    432
    My Mood
    Depressed
    Thanks
    54
    Thanked 67 Times in 67 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    He still hasn't replied yet. It's got to be something really simple yet I can't figure it out. I have looked and looked. There seems to be no way to get the Graphics object.

    It is driving me NUTS! I cannot figure out how to do it. I know that going through PrinterJob is still doing it on two pages. I cannot have it doing only 1 thing per page. That is WAY too wasteful.

    I tried the getGraphics() and that failed.

    I thought of using the print(Graphics g) method from JComponent but that also I think would require getting a Graphics object from somewhere outside of the safety of one of those methods that takes a Graphics object parameter. (And anyway, I don't think that the JComponent print method works with printers in that way. Could be wrong. I tried using it once and it did wacky things.)


    I also know that the change he wants can't possibly be intended to be inside the print() method that he had.

    I've no clue what he meant.


    JavaScript is NOT Java.

  3. #3
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    432
    My Mood
    Depressed
    Thanks
    54
    Thanked 67 Times in 67 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    Still no reply from him. Maybe someone here can help. I can tell him I got help. I'm not understanding how he wants me to do it without using PrinterJob (which does it on separate pages).

    I'm thinking of just scrapping his idea and taking the text and putting it into an invisible JTextPane (though I don't quite know how to use those as they are harder to work than a JTextArea) and have the JTable and the text I want go there and even be formatted (don't quite know how to do the formatting part but the internet is very helpful (er, usually).)
    JavaScript is NOT Java.

  4. #4
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    432
    My Mood
    Depressed
    Thanks
    54
    Thanked 67 Times in 67 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    Ok, still haven't found out what to do. The idea that java doesn't have some way to get it to print two JTables or more than one component on the same page, even if there is room, seems a very big flaw in java indeed if it is true that it's not possible.

    I've found stuff for PrintPreview (though again, that print preview thing only shows one component at a time.)

    Still nothing for how to handle multiple JTables to print on a same page if it's possible for them to fit on the same page.

    I think an idea for the solution to this might involve the Graphics class.

    If there was a way I could get an image or turn each component into a Graphics image and then try and combine as many of those images as I could on a single page, it might work.

    I'm currently looking at the getPrintable() to see if there is a way to do this.


    In the print method of Printable, there seems to be a PageFormat object and a Graphics object.

    I'm wondering if the Paper object I can get can help any. Something tells me it can't.

    Ok, the getGraphics() might work with a BufferedImage and I found some code here that would help with that, at least I hope so.

    So then I could combine stuff into a JLabel. Problem is, I don't think JLabel has a print method.

    So that won't quite work.

    Even very old languages have a way to do it on one page. Why is java so difficult?


    How do I get this code to print out both JTables on the same page?

     
     
    import javax.swing.JTable;
    import javax.swing.JPanel;
    import javax.swing.JFrame;
    import javax.swing.JScrollPane;
     
     
    public class PrintTwoThingsOnOnePage extends JFrame
    {
     
     
     
       public PrintTwoThingsOnOnePage()
       {
     
     
          JPanel jp = new JPanel();
     
          add(jp);
     
          jp.setLayout(new java.awt.BorderLayout());
     
          Object[][] cols = new Object[2][2];
     
          for (int i=0; i < cols.length; i++)
          {
     
             for (int j = 0; j < cols[i].length; j++)
             {
                cols[i][j] = i+j;
     
             }
          }
     
          Object[] rows = new Object[2];
     
          rows[0] = "Democrat";
          rows[1] = "Republican";
     
     
     
          JTable jt = new JTable(cols, rows);
     
          jp.add(new JScrollPane(jt, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), java.awt.BorderLayout.NORTH);
     
          setVisible(true);
     
          Object[][] cols2 = new Object[3][3];
     
          for (int m =0; m < cols2.length; m++)
          {
     
             for (int n =0; n < cols2[m].length; n++)
             {
                cols2[m][n] = m + n;
     
             }
     
          }
     
          Object[] rows2 = new Object[3];
     
          rows2[0] = "Democrat";
          rows2[1] = "Republican";
          rows2[2] = "Tea Party";
     
          JTable jt2 = new JTable(cols2, rows2);
     
          jp.add(new JScrollPane(jt2, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), java.awt.BorderLayout.CENTER);
     
          setDefaultCloseOperation(EXIT_ON_CLOSE);
       }
     
       public static void main(String[] args)
       {
     
          new PrintTwoThingsOnOnePage();
     
       }
     
     
     
     
    }

    I've looked up stuff all over the place and nothing so far seems to work for what I want.
    Last edited by GoodbyeWorld; February 21st, 2015 at 06:09 PM.
    JavaScript is NOT Java.

  5. #5
    Member
    Join Date
    Feb 2015
    Posts
    82
    Thanks
    3
    Thanked 17 Times in 17 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    The reason you graphics is null is because it has never been validated. Try:
    JTable table = new JTable(rows, data);
            JFrame frame = new JFrame();
            frame.setSize(200, 200);
            frame.add(table);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
    To validate the graphics - this will eliminate your error - but I suspect you are missing something - You need a printer job to actually print something.

  6. #6
    Elite Member
    Join Date
    Jul 2013
    Location
    Europe
    Posts
    1,318
    Thanks
    0
    Thanked 236 Times in 216 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    You could simply have your components be painted inside a BufferedImage and then print the BufferedImage can you not?

    Just do the following:
    1) Create a new BufferedImage of your desired proportions (use INT_ARGB for the color type)
    2) Have the BufferedImage create a Graphics object for you
    3) Pass this Graphics object into the paintComponent methods of your JComponents, this way you draw your GUI into the BufferedImage that created the Graphics
    4) Print the BufferedImage

    I never tried this myself but in theory it should be good.

  7. The Following User Says Thank You to Cornix For This Useful Post:

    GoodbyeWorld (February 21st, 2015)

  8. #7
    Member
    Join Date
    Feb 2015
    Posts
    82
    Thanks
    3
    Thanked 17 Times in 17 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    Add the following method to actually send the printable to a printer:
         public void printIt()
         {
            PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();;
            PrinterJob job = PrinterJob.getPrinterJob();
            try
            {
                job.setPrintable(this);
                if(job.printDialog(attributes))
                    job.print(attributes);
            }
            catch (PrinterException e)
            {
                JOptionPane.showMessageDialog(null, e);
            }
         }

    This will actually send the printable to a printer - call it after you have printed to the printable:
        public static void main(String[] args)
        {
            Object[][] rows = new Object[2][2];
            for (int i =0; i < rows.length; i++)
            {
                for (int j=0; j < rows[i].length; j++)
                {
                    rows[i][j] = i*j;
                }
            }
            Object[] data = new Object[2];
            data[0] = "Mike";
            data[1] = "Bob";
     
            JTable table = new JTable(rows, data);
            JFrame frame = new JFrame();
            frame.setSize(200, 200);
            frame.add(table);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
            MyPrintable prt = new MyPrintable(table.getPrintable(javax.swing.JTable.PrintMode.NORMAL, null, null));
            int pageIndex = 0;
            try
            {
                while (prt.print(table.getGraphics(), new java.awt.print.PageFormat(),pageIndex) == PAGE_EXISTS)
                {
                    if (prt.getSpaceLeft() < 100)
                    {
                        // create a new page or a new graphics
                        // reset page index to 0
                    }
                    pageIndex++;
                }
                // looping to the next Printable...
            }
            catch(PrinterException pe)
            {
                pe.printStackTrace();
            }
            prt.printIt();
        }

    Hope this points you in the right direction

  9. The Following User Says Thank You to rpw For This Useful Post:

    GoodbyeWorld (February 21st, 2015)

  10. #8
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    432
    My Mood
    Depressed
    Thanks
    54
    Thanked 67 Times in 67 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    So, I don't have to nest JTables to do it? (That was another idea I had come up with while waiting for a reply. That one appears to work, though I'll try your advice too.)

    --- Update ---

    Quote Originally Posted by rpw View Post
    Add the following method to actually send the printable to a printer:
         public void printIt()
         {
            PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();;
            PrinterJob job = PrinterJob.getPrinterJob();
            try
            {
                job.setPrintable(this);
                if(job.printDialog(attributes))
                    job.print(attributes);
            }
            catch (PrinterException e)
            {
                JOptionPane.showMessageDialog(null, e);
            }
         }

    This will actually send the printable to a printer - call it after you have printed to the printable:
        public static void main(String[] args)
        {
            Object[][] rows = new Object[2][2];
            for (int i =0; i < rows.length; i++)
            {
                for (int j=0; j < rows[i].length; j++)
                {
                    rows[i][j] = i*j;
                }
            }
            Object[] data = new Object[2];
            data[0] = "Mike";
            data[1] = "Bob";
     
            JTable table = new JTable(rows, data);
            JFrame frame = new JFrame();
            frame.setSize(200, 200);
            frame.add(table);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
            MyPrintable prt = new MyPrintable(table.getPrintable(javax.swing.JTable.PrintMode.NORMAL, null, null));
            int pageIndex = 0;
            try
            {
                while (prt.print(table.getGraphics(), new java.awt.print.PageFormat(),pageIndex) == PAGE_EXISTS)
                {
                    if (prt.getSpaceLeft() < 100)
                    {
                        // create a new page or a new graphics
                        // reset page index to 0
                    }
                    pageIndex++;
                }
                // looping to the next Printable...
            }
            catch(PrinterException pe)
            {
                pe.printStackTrace();
            }
            prt.printIt();
        }

    Hope this points you in the right direction
    I'm not sure how that code will work if I want more than one Printable on the same page. It may help breaking up a Printable onto multiple pages (thought Java already handled that anyway) but not getting two JTables to fit on the same page and only going onto other pages if it has to.

    --- Update ---

    Quote Originally Posted by Cornix View Post
    You could simply have your components be painted inside a BufferedImage and then print the BufferedImage can you not?

    Just do the following:
    1) Create a new BufferedImage of your desired proportions (use INT_ARGB for the color type)
    2) Have the BufferedImage create a Graphics object for you
    3) Pass this Graphics object into the paintComponent methods of your JComponents, this way you draw your GUI into the BufferedImage that created the Graphics
    4) Print the BufferedImage

    I never tried this myself but in theory it should be good.
    That might work, though what if the image does go onto more than one page? I mean, what if it's a page and a half after I combine the images?
    JavaScript is NOT Java.

  11. #9
    Member
    Join Date
    Feb 2015
    Posts
    82
    Thanks
    3
    Thanked 17 Times in 17 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    I think you are over complicating the Printing process - You simply override the print method of the Printable to print - It is up to you to keep track of pages on the Graphics. Take a look at the following:
    import java.awt.print.*;
    import java.util.*;
    import javax.swing.*;
    import java.awt.*;
    import javax.print.attribute.HashPrintRequestAttributeSet;
    import javax.print.attribute.PrintRequestAttributeSet;
     
    public class Main 
    {    
        public static void main(String args[]) 
        { 
            Object[][] rowsOne = new Object[2][2];
            for (int i =0; i < rowsOne.length; i++)
            {
                for (int j=0; j < rowsOne[i].length; j++)
                {
                    rowsOne[i][j] = i*j;
                }
            }
            Object[] data = new Object[2];
            data[0] = "Mike";
            data[1] = "Bob";
            Object[][] rowsTwo = new Object[2][2];
            for (int i =0; i < rowsTwo.length; i++)
            {
                for (int j=0; j < rowsTwo[i].length; j++)
                {
                    rowsTwo[i][j] = i+j;
                }
            }
     
            JTable tableOne = new JTable(rowsOne, data);
            JTable tableTwo = new JTable(rowsTwo, data);
     
            JPanel panel = new JPanel();
            panel.setLayout(new GridLayout(2,1));
            panel.add(tableOne);
            panel.add(tableTwo);
            JFrame frame = new JFrame();
            frame.setSize(300, 300);
            frame.add(panel);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
     
            MyPrintable prt = new MyPrintable();
            prt.addComponent(tableOne);
            prt.addComponent(tableTwo);
            prt.printIt();
        }
    }
     
    class MyPrintable implements Printable
    {
        private ArrayList<JComponent> items;
     
        public MyPrintable()
        {
            items = new ArrayList<>();
        }
        @Override
        public int print(Graphics g, PageFormat pf, int page) throws PrinterException
        {
            if(page > 0) return Printable.NO_SUCH_PAGE;
            Graphics2D g2 = (Graphics2D)g;
            g2.translate(pf.getImageableX(), pf.getImageableY());
     
            for(JComponent item : items)
            {
                item.printAll(g);
                g2.translate(0, item.getHeight());
            }
            return Printable.PAGE_EXISTS;
        }
     
        public void printIt()
        {
            PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();;
            PrinterJob job = PrinterJob.getPrinterJob();
            try
            {
                job.setPrintable(this);
                if(job.printDialog(attributes))
                    job.print(attributes);
            }
            catch (PrinterException e)
            {
                JOptionPane.showMessageDialog(null, e);
            }
        }
     
        public void addComponent(JComponent component) { items.add(component); }
    }

    You will have to decide how much and how many tables can be printed on a page - If all components always fit on one page than the above will work. Print is called from the Job for each page until there are no more pages. Also, you actually need a table that is validated or it will not print. I have validated them in the JFrame on the JPanel.
    Last edited by rpw; February 21st, 2015 at 10:01 PM. Reason: Confusing

  12. The Following User Says Thank You to rpw For This Useful Post:

    GoodbyeWorld (February 21st, 2015)

  13. #10
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    432
    My Mood
    Depressed
    Thanks
    54
    Thanked 67 Times in 67 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    What will I have to modify on the above if they don't (which is a possibility, especially as the program will allow the user to add stuff to the table, including rows)?

    What will I do with this code:

     
      MyPrintable prt = new MyPrintable(table.getPrintable(javax.swing.JTable.PrintMode.NORMAL, null, null));
            int pageIndex = 0;
            try
            {
                while (prt.print(table.getGraphics(), new java.awt.print.PageFormat(),pageIndex) == PAGE_EXISTS)
                {
                    if (prt.getSpaceLeft() < 100)
                    {
                        // create a new page or a new graphics
                        // reset page index to 0
                    }
                    pageIndex++;
                }
                // looping to the next Printable...
            }
            catch(PrinterException pe)
            {
                pe.printStackTrace();
            }
            prt.printIt();


    That part, I'm hoping, will be able to tell if it needs to go to a new page.
    Last edited by GoodbyeWorld; February 21st, 2015 at 10:29 PM.
    JavaScript is NOT Java.

  14. #11
    Member
    Join Date
    Feb 2015
    Posts
    82
    Thanks
    3
    Thanked 17 Times in 17 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    import java.awt.print.*;
    import java.util.*;
    import javax.swing.*;
    import java.awt.*;
    import javax.print.attribute.HashPrintRequestAttributeSet;
    import javax.print.attribute.PrintRequestAttributeSet;
     
    public class Main 
    {    
        public static void main(String args[]) 
        { 
            Object r1[][] = {   { "T1-R1C1", "T1-R1C2", "T1-R1C3", "T1-R1C4" },
                                { "T1-R2C1", "T1-R2C2", "T1-R2C3", "T1-R2C4" } };
            Object c1[] = { "Column One", "Column Two", "Column Three", "Column Four"};
            JTable t1 = new JTable(r1, c1);
            //Please note the default column width is 75 as per Swing
            //You may need to calculate out column widths and set them your self
            t1.setSize(t1.getColumnModel().getTotalColumnWidth(), t1.getRowHeight() * t1.getRowCount());
     
            Object r2[][] = {   { "T2-R1C1", "T2-R1C2", "T2-R1C3" },
                                { "T2-R2C1", "T2-R2C2", "T2-R2C3" },
                                { "T2-R3C1", "T2-R3C2", "T2-R3C3" } };
            Object c2[] = { "Column One", "Column Two", "Column Three"};
            JTable t2 = new JTable(r2, c2);
            t2.setSize(t2.getColumnModel().getTotalColumnWidth(), t2.getRowHeight() * t2.getRowCount());
     
            Object r3[][] = {   { "T3-R1C1", "T3-R1C2" },
                                { "T3-R2C1", "T3-R2C2" },
                                { "T3-R3C1", "T3-R3C2" },
                                { "T3-R4C1", "T3-R4C2" },
                                { "T3-R5C1", "T3-R5C2" },
                                { "T3-R6C1", "T3-R6C2" },
                                { "T3-R7C1", "T3-R7C2" },
                                { "T3-R8C1", "T3-R8C2" },
                                { "T3-R9C1", "T3-R9C2" } };
            Object c3[] = { "Column One", "Column Two"};
            JTable t3 = new JTable(r3, c3);
            t3.setSize(t3.getColumnModel().getTotalColumnWidth(), t3.getRowHeight() * t3.getRowCount());
     
            MyPrintable prt = new MyPrintable();
            //Just for testing add the tables 4 times
            for(int i = 0; i < 4; i++)
            {
                prt.addComponent(t1);
                prt.addComponent(t2);
                prt.addComponent(t3);
            }
            prt.printIt();
        }
    }
     
    class MyPrintable implements Printable
    {
        private ArrayList<JComponent> items;
     
        public MyPrintable()
        {
            items = new ArrayList<>();
        }
     
        //Note this just continues to print components picking up where
        //they left off on the last page - You will need more logic to
        //make it look good i.e. break pages on components.
        @Override
        public int print(Graphics g, PageFormat pf, int page) throws PrinterException
        {
            Graphics2D g2 = (Graphics2D)g;
     
            int pageOffset = (int)pf.getImageableHeight() * page;
            g2.translate(pf.getImageableX(), pf.getImageableY() - pageOffset);
            int y = 0;
            for(JComponent item : items)
            {
                item.printAll(g);
                g2.translate(0, item.getHeight());
                y += item.getHeight();
            }
            if(y < pageOffset)
                return Printable.NO_SUCH_PAGE;
            return Printable.PAGE_EXISTS;
        }
     
        public void printIt()
        {
            PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();;
            PrinterJob job = PrinterJob.getPrinterJob();
            try
            {
                job.setPrintable(this);
                if(job.printDialog(attributes))
                    job.print(attributes);
            }
            catch (PrinterException e)
            {
                JOptionPane.showMessageDialog(null, e);
            }
        }
     
        public void addComponent(JComponent component) { items.add(component); }
    }

    Basically this is just printing everything and translating the starting point depending on the page. You get the idea. When you have nothing left to print return a Printable.NO_SUCH_PAGE and that will complete the printing. You will have to figure out the geometry if you want to break pages between tables. Note, I am not validating the JTables on a JFrame therefore I have to manually set the size. Hopefully this will help you see what you need to do.

    As far as the code you started with - I am not sure what is going on there - The printer job calls print in the printable - you probably shouldn't be calling print directly - The printer job repeatedly calls print and increments the page number on each call until Printable.NO_SUCH_PAGE is returned it only sends the graphics to the printer when Printable.PAGE_EXISTS is returned. (Note the above is not entirely correct: The print job calls print with a page number to determine if there is something to print, then it call print again with the same page number and actually prints the graphics.)
    Last edited by rpw; February 22nd, 2015 at 05:59 AM.

  15. The Following User Says Thank You to rpw For This Useful Post:

    GoodbyeWorld (February 22nd, 2015)

  16. #12
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    432
    My Mood
    Depressed
    Thanks
    54
    Thanked 67 Times in 67 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    Ok, I can see this wasn't as easy as I had thought at first though apparently not as extremely difficult as I later thought.


    I'm confused with all of this validating and other things you are talking about.

    The code I started with I found online. I've been trying to find a solution to do this online. I'm totally baffled with the deeper parts of the printing code as it involves some APIs I'm not too familiar with.

    I kind of know the Graphics API, though the translate part I cannot know if it's correct.

    I've found that the code above doesn't know where the page ends and that's a problem as it cuts off part of stuff. I cannot for the life of me figure this out as all of this Graphics stuff is over my head. I'd never be able to get it. I see kind of what the code is doing, though I'm not sure how I'd be able to make it so that it doesn't cut off at the very bottom of the page as it won't do to have half of that part of the table on one page and the other half on the other. I'd rather have it send it all over to the next page rather than cut it off. However, I'd NEVER be able to figure it out as the translation and other things in graphics has always given me problems and I wouldn't be able to tell where it was cut off anyway.

    I also don't know how to get it to do the headers. I was able to do it on nested tables with:

     
    import java.awt.Component;  
    import java.awt.Container;  
    import java.awt.event.MouseEvent;  
    import java.awt.event.MouseMotionListener;  
     
    import javax.swing.AbstractCellEditor;  
    import javax.swing.JFrame;  
    import javax.swing.JScrollPane;  
    import javax.swing.JTable;  
    import javax.swing.table.DefaultTableCellRenderer;  
    import javax.swing.table.DefaultTableModel;  
    import javax.swing.table.TableCellEditor;  
    import javax.swing.table.TableColumn;  
    import javax.swing.table.TableColumnModel;  
     
     
    public class TestNestedJTable extends JFrame{  
       private static final long serialVersionUID = -722808327091366767L;  
     
       private JTable mainTable;  
       private JTable leftTable;  
       private JTable rightTable;  
       private Object[][] tableList;  
       private Container container;  
     
       private String[] columnNames = {"First Name",  
              "Last Name",  
              "Sport",  
              "# of Years",  
              "Vegetarian"};  
       private Object[][] data = {  
              {"Mary", "Campione",  
              "Snowboarding", new Integer(5), new Boolean(false)},  
              {"Alison", "Huml",  
              "Rowing", new Integer(3), new Boolean(true)},  
              {"Kathy", "Walrath",  
              "Knitting", new Integer(2), new Boolean(false)},  
              {"Sharon", "Zakhour",  
              "Speed reading", new Integer(20), new Boolean(true)},  
              {"Philip", "Milne",  
              "Pool", new Integer(10), new Boolean(false)},  
       };  
       private String[] columnNames2 = {"",  
              "Last Name",  
              "Group",  
              "Year"};  
       private Object[][] data2 = {  
              {false, "Li",  
              "Tiger", new Integer(1997), },  
              {false, "Roy",  
              "Lion", new Integer(1996)},  
              {false, "Lee",  
              "Dragon", new Integer(1989)},  
              {false, "Jones",  
              "Lion", new Integer(1981)},  
              {false, "Lam",  
              "Dragon", new Integer(1980)},  
       };  
     
       private String[] names = {"sdf", "sdf", "dfs"};  
     
       public TestNestedJTable(){  
          container = this.getContentPane();  
     
          leftTable = new JTable(data, columnNames);  
          rightTable = new JTable(data2, columnNames2);  
          leftTable.getTableHeader().setVisible(true);  
          rightTable.getTableHeader().setVisible(true);  
     
          tableList = new Object[1][];  
          tableList[0] = new Object[3];  
          tableList[0][0] = leftTable;  
          tableList[0][1] = rightTable;  
          tableList[0][2] = "dfgfdg";  
     
          mainTable = new JTable(new DefaultTableModel(tableList, names));  
     
          TableColumn tc = mainTable.getColumnModel().getColumn(0);  
          tc.setCellRenderer(new CustomTableCellRenderer(leftTable));  
          tc.setCellEditor(new CustomTableCellEditor(leftTable));  
          tc = mainTable.getColumnModel().getColumn(1);  
          tc.setCellRenderer(new CustomTableCellRenderer(rightTable));  
          tc.setCellEditor(new CustomTableCellEditor(rightTable));  
          mainTable.setRowHeight(leftTable.getPreferredSize().height+leftTable.getTableHeader().getPreferredSize().height+4);  
     
          mainTable.addMouseMotionListener(new MyMouseMotionListener());  
     
          // Enable the ability to select a single cell   
          mainTable.setColumnSelectionAllowed(true);   
          mainTable.setRowSelectionAllowed(true);   
     
          container.add(new JScrollPane(mainTable));  
     
          setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );  
          this.pack();  
          setSize(500,500);  
          setVisible(true);  
     
     
          javax.swing.JButton jb = new javax.swing.JButton("Print");
          container.add(jb, java.awt.BorderLayout.SOUTH);
     
          jb.addActionListener(new java.awt.event.ActionListener() {
     
          public void actionPerformed(java.awt.event.ActionEvent e)
          {
     
          try
          {
          mainTable.print();
          }
     
          catch(java.awt.print.PrinterException pe)
          {
     
     
          }
     
          }});
       }  
     
     
       class CustomTableCellRenderer extends DefaultTableCellRenderer {  
          private static final long serialVersionUID = 4415155875184525824L;  
          JTable table;  
     
          CustomTableCellRenderer(JTable table){  
             this.table=table;  
             this.table.setOpaque(true);  
             this.table.setAlignmentY(JTable.LEFT_ALIGNMENT);  
          }  
     
          @Override  
          public Component getTableCellRendererComponent(JTable table, Object value,  
                  boolean isSelected, boolean hasFocus, int row, int column) {  
             this.table=(JTable)value;  
             return new JScrollPane(this.table);   
          }  
       }  
     
       class CustomTableCellEditor extends AbstractCellEditor implements TableCellEditor{  
     
          JTable table;  
     
          CustomTableCellEditor(JTable table){  
             this.table=table;  
             this.table.setOpaque(true);  
             this.table.setAlignmentY(JTable.LEFT_ALIGNMENT);  
          }  
     
          @Override  
          public Component getTableCellEditorComponent(JTable table,  
                  Object value, boolean isSelected, int row, int column) {  
             this.table=(JTable)value;  
             return new JScrollPane(this.table);  
          }  
     
          @Override  
          public Object getCellEditorValue() {  
             return this.table;  
          }  
     
       }  
     
       class MyMouseMotionListener implements MouseMotionListener{  
     
          @Override  
          public void mouseDragged(MouseEvent e) {  
          }  
     
          @Override  
          public void mouseMoved(MouseEvent e) {  
             if(e.getComponent() instanceof JTable){  
                JTable tempTable = (JTable)e.getComponent();  
     
                TableColumnModel columnModel = tempTable.getColumnModel();  
                int viewColumn = columnModel.getColumnIndexAtX(e.getX());  
                int column = columnModel.getColumn(viewColumn).getModelIndex();  
                int row = tempTable.rowAtPoint(e.getPoint());  
     
                // change the if-statement to the columns you want to programmatically   
                // enter edit mode of, when the mouse is over it.  
                if(column==0 || column==1){  
                   // Set the cell on the row and column in edit mode   
                   boolean success = tempTable.editCellAt(row, column);  
                   if (success) {  
                      boolean toggle = false;  
                      boolean extend = false;  
                    // Select cell   
                      tempTable.changeSelection(row, column, toggle, extend);  
                   }  
                }  
             }  
          }  
       }  
     
       /** 
        * @param args 
        */  
       public static void main(String[] args) {  
          new TestNestedJTable();  
       }  
    }

    (Note: I got that online too so I don't fully know what it does either. I'm way over my head with all of this Graphics stuff. I kind of get what my code above does, though not what made it print the headers.)

    I kind of might be able to figure out what the other stuff does, er, eventually, but the Graphics stuff seems like it's going to be rather tricky.

    I figured that somebody had to have tried this before in java as it's so standard, but I have yet to find one that really does what I want (and I've spent countless hours looking on Google too).
    Last edited by GoodbyeWorld; February 22nd, 2015 at 06:50 PM.
    JavaScript is NOT Java.

  17. #13
    Member
    Join Date
    Feb 2015
    Posts
    82
    Thanks
    3
    Thanked 17 Times in 17 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    When I say validating I just mean that the table has been draw on a JComponent thus all the sizes (cell width, cell height, overall width, overall height) have been calculated and set - otherwise the table will not show up when you paint (or print) it on a graphics. The additional logic for splitting pages between components is fairly simple. The problem comes when you actually have to split to table between rows if the table will not fit on one page.

    This modified print will avoid splitting components unless the component is bigger than a page.
        @Override
        public int print(Graphics g, PageFormat pf, int page) throws PrinterException
        {
            int componentGap = 10;
     
            Graphics2D g2 = (Graphics2D)g;
     
            int pageHeight = (int)pf.getImageableHeight();
            int pageOffset = pageHeight * page;
            g2.translate(pf.getImageableX(), pf.getImageableY() - pageOffset);
            int y = 0;
            for(JComponent item : items)
            {
                int h = item.getHeight() + componentGap;
                for(int i = 0; i <= page; i++)
                {
                    if(y > i * pageHeight && y < (i + 1) * pageHeight && y + h > (i + 1) * pageHeight)
                    {
                        int delta = ((i + 1)*pageHeight - y);
                        g2.translate(0, delta);
                        y += delta;
                        break;        
                    }
                }
                item.printAll(g);
                g2.translate(0, h);
                y += h;
            }
            if(y < pageOffset)
                return Printable.NO_SUCH_PAGE;
            return Printable.PAGE_EXISTS;
        }

    [Edit] In your example putting the table in a JScrollPane made it print the headers.
    Last edited by rpw; February 22nd, 2015 at 08:42 PM.

  18. The Following User Says Thank You to rpw For This Useful Post:

    GoodbyeWorld (February 22nd, 2015)

  19. #14
    Member
    Join Date
    Feb 2015
    Posts
    82
    Thanks
    3
    Thanked 17 Times in 17 Posts

    Default Re: Trying to figure out how to print multiple things on same page

    The following may be more what you are looking for. With this print method it looks if it is a JTable and uses the Printable for the JTable class - I think that is what your original code was trying to do. I also modified the main method to provide a better example.

    import java.awt.print.*;
    import java.util.*;
    import javax.swing.*;
    import java.awt.*;
    import javax.print.attribute.HashPrintRequestAttributeSet;
    import javax.print.attribute.PrintRequestAttributeSet;
     
    public class Main 
    {    
        public static void main(String args[]) 
        { 
            Object[][] r1 = new Object[20][4];
            for(int i = 0; i < r1.length; i++)
                for(int j = 0; j < r1[i].length; j++)
                    r1[i][j] = "T1-R"+i+"C"+j;
            Object[] c1 = { "T1-H1", "T1-H2", "T1-H3", "T1-H4" };
            JTable t1 = new JTable(r1, c1);
            JScrollPane s1 = new JScrollPane(t1);
            JLabel l1 = new JLabel("This is Table One");
     
            Object[][] r2 = new Object[5][4];
            for(int i = 0; i < r2.length; i++)
                for(int j = 0; j < r2[i].length; j++)
                    r2[i][j] = "T2-R"+i+"C"+j;
            Object[] c2 = { "T2-H1", "T2-H2", "T2-H3", "T2-H4" };
            JTable t2 = new JTable(r2, c2);
            JScrollPane s2 = new JScrollPane(t2);
            JLabel l2 = new JLabel("This is Table Two");
     
            Object[][] r3 = new Object[4][3];
            for(int i = 0; i < r3.length; i++)
                for(int j = 0; j < r3[i].length; j++)
                    r3[i][j] = "T2-R"+i+"C"+j;
            Object[] c3 = { "T2-H1", "T2-H2", "T2-H3" };
            JTable t3 = new JTable(r3, c3);
            JScrollPane s3 = new JScrollPane(t3);
            JLabel l3 = new JLabel("This is Table Three");
     
            JPanel panel = new JPanel();
            panel.setLayout(new GridLayout(6,1));
            panel.add(l1);
            panel.add(s1);
            panel.add(l2);
            panel.add(s2);
            panel.add(l3);
            panel.add(s3);
     
            JFrame frame = new JFrame();
            frame.setSize(500, 500);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(panel);
            frame.setVisible(true);
     
            MyPrintable prt = new MyPrintable();
            prt.addComponent(l1);
            prt.addComponent(t1);
            prt.addComponent(l2);
            prt.addComponent(t2);
            prt.addComponent(l3);
            prt.addComponent(t3);
     
            prt.printIt();
        }
    }
     
    class MyPrintable implements Printable
    {
        private ArrayList<JComponent> items;
     
        public MyPrintable()
        {
            items = new ArrayList<>();
        }
     
        @Override
        public int print(Graphics g, PageFormat pf, int page) throws PrinterException
        {
            int componentGap = 10;
     
            Graphics2D g2 = (Graphics2D)g;
     
            int pageHeight = (int)pf.getImageableHeight();
            int pageOffset = pageHeight * page;
            g2.translate(pf.getImageableX(), pf.getImageableY() - pageOffset);
            int y = 0;
            for(JComponent item : items)
            {
     
                int h = item.getHeight() + componentGap;
                for(int i = 0; i <= page; i++)
                {
                    if(y > i * pageHeight && y < (i + 1) * pageHeight && y + h > (i + 1) * pageHeight && h < pageHeight)
                    {
                        int delta = ((i + 1)*pageHeight - y);
                        g2.translate(0, delta);
                        y += delta;
                        break;        
                    }
                }
                if(item.getClass().isInstance(new JTable()))
                {
                    JTable table = (JTable)item;
                    Printable pr = table.getPrintable(JTable.PrintMode.FIT_WIDTH, null, null);
                    int k = 0;
                    Paper paper = new Paper();
                    paper.setImageableArea(0, 0, pf.getImageableWidth(), h);
                    PageFormat pg = new PageFormat();
                    pg.setPaper(paper);
                    while(pr.print(g, pg, k) == Printable.PAGE_EXISTS) k++;
                }
                else
                    item.printAll(g);
                g2.translate(0, h);
                y += h;
            }
            if(y < pageOffset)
                return Printable.NO_SUCH_PAGE;
            return Printable.PAGE_EXISTS;
        }
     
        public void printIt()
        {
            PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();;
            PrinterJob job = PrinterJob.getPrinterJob();
            try
            {
                job.setPrintable(this);
                if(job.printDialog(attributes))
                    job.print(attributes);
            }
            catch (PrinterException e)
            {
                JOptionPane.showMessageDialog(null, e);
            }
        }
     
        public void addComponent(JComponent component) { items.add(component); }
    }
    Last edited by rpw; February 22nd, 2015 at 11:13 PM.

  20. The Following User Says Thank You to rpw For This Useful Post:

    GoodbyeWorld (February 22nd, 2015)

Similar Threads

  1. Replies: 6
    Last Post: July 6th, 2013, 08:54 PM
  2. Replies: 1
    Last Post: December 3rd, 2012, 01:35 PM
  3. xfa.host.print: print a page + some page range.
    By gammaman in forum Totally Off Topic
    Replies: 2
    Last Post: May 10th, 2012, 08:07 AM
  4. Can't figure out how to print out number of lines and words in a file in c++
    By javapenguin in forum Other Programming Languages
    Replies: 1
    Last Post: January 29th, 2012, 06:53 PM
  5. [SOLVED] Define a String as multiple things
    By bgroenks96 in forum Java Theory & Questions
    Replies: 10
    Last Post: June 7th, 2011, 09:57 AM

Tags for this Thread