0

Yo dudes. I need so suggestions on how to best implement something please. My program:

I have a swing program that reads a file with multiple records of different types. I read these records into java objects, make JTables of them with their headings and content (so every table only has the heading and 1 record), add these tables to a panel and add the panel to a scrollpane. There are lots of records, about 70000, so i cant load everything into memory at once.

My plan is to paginate the display by only displaying say 100 records at a time, and if you scroll past a certain point, lets say table nr 50, it will load the next 100 tables and add them to the scrollpane.

This brings me to my questions

1) Im not sure how to notify myself that ive scrolled past a certain point. So given that i have 100 JTables attached to a JPanel attached to a scrollpane. How can i add a listener to notify when the user has scrolled past say Jtable 50 for arguments sake.

2) The other issue im having is related to how i put my tables into the panel. Im using a swingworker as below:

private class TableRun extends SwingWorker<Void, JTable> {

        private ArrayDeque<FileRecord> fileRecords;
        private final GridBagConstraints gc;
        private final JPanel parentPanel;
        int counter = 1;

        TableRun(ArrayDeque<FileRecord> fileRecords, GridBagConstraints gc, JPanel parentPanel) {
            this.fileRecords = fileRecords;
            this.gc = gc;
            this.parentPanel = parentPanel;
        }

        @Override
        protected Void doInBackground() {
            Iterator<FileRecord> iterator = fileRecords.iterator();
            while (iterator.hasNext()) {
                publish(getTabel(iterator.next()));
            }

            return null;
        }

        @Override
        protected void process(final List<JTable> tables) {
                    Iterator<JTable> iterator = tables.iterator();
                    while(iterator.hasNext()) {
                        JTable table = iterator.next();
                        gc.fill = 1;
                        parentPanel.add(table.getTableHeader(), gc);
                        gc.gridy++;
                        parentPanel.add(table,gc);
                        gc.gridy++;

                        //validate takes a long time so i try to not do it too often.
                        if(counter == 50 || (counter % 5000) ==0 || (counter == fileRecords.size())) {
                            validate();
                        }
                        System.out.println("Sequence Nr : " + table.getModel().getValueAt(0,1) + " - Counter :" + counter++);
                    }
        }
    }

I feed my record objects to the swingworker. It then converts the record into the JTable with all the necessary formatting, then it adds them to the panel. It sometimes calls validate in order to display the tables, else it doesnt display them. (not sure if theres a better way to do this?)

So my question is related to the scrolling. If i initially only feed 100 of the 70000 records to my swinworker it obviously creates the scrollpane thinking theres only 100 records. So the scrollbar isnt very small (ie its clear that you cant scroll very far). What i actually want is that even though im only showing 100 records, i want the size of the scrollpane to be that of 70000 records so that you can see the size of the records based on the scrollbar. If you drag the scrollbar to some point at the bottom it them needs to pull and display those records. How can i create the size of my scrollpane bigger than the actual components in it, but based on their size?

hope my question makes sense

Thanks

mKorbel
  • 109,525
  • 20
  • 134
  • 319
3uPh0riC
  • 480
  • 1
  • 4
  • 18
  • hard to answering something cleaver because everything in protected void process(final List tables) { is wrong (theoretically each of records re_creating whole JTable, sure have to waiting maybe someone to share her/his attempts) – mKorbel Jan 21 '14 at 08:25
  • never to create any Swing GUI inside Workers Thread or try - catch - finally block, GUI should be ready (intialized, laid) before Workers Thread is started – mKorbel Jan 21 '14 at 08:27
  • stupid question ---> please is there any reason to ignore [answer and linked code in answer by @trashgod](http://stackoverflow.com/a/21134944/714968) – mKorbel Jan 21 '14 at 08:47
  • what does workers thread should be ready initialised before workers thread is started mean? The whole reason i tried to use a swingworker is because i cant create 70000 Jtables all at once up front, it kills my system. Im not understanding someting, please help. If i shouldnt use Swingworker to create my components and "its all wrong" please assist by pointing me in the right direction instead of just saying its wrong. – 3uPh0riC Jan 21 '14 at 08:52
  • SwingWorker (Workers Thread, Background task)isn't place to create or laid any GUI in any of PLs, there you can to fetch data to model, SwingWorker is designated for Background task – mKorbel Jan 21 '14 at 09:00
  • Okay so what if i remove the swingworker, my original questions are still valid... i still know how to accomplish what i need to – 3uPh0riC Jan 21 '14 at 09:52

1 Answers1

1

How can i add a listener to notify when the user has scrolled past say Jtable 50 for arguments sake.

for example (one of possible ways, you can to test for oneRectangle.intersects(anotherRectangle)), (apologize me) rest of questions isn't answerable, note and you have to redispatch mouse events (mouse wheel) from parent (JScrollPane contains JPanel) to childs contains JTables

enter image description here

.

enter image description here

.

enter image description here

.

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.RepaintManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.TableModel;

//http://stackoverflow.com/a/8249353/714968
public class ViewPortFlickeringOriginal {

    private JFrame frame = new JFrame("Table");
    private JViewport viewport = new JViewport();
    private Rectangle RECT = new Rectangle();
    private Rectangle RECT1 = new Rectangle();
    private JTable table = new JTable(50, 3);
    private javax.swing.Timer timer;
    private int count = 0;
    private boolean topOrBottom = false;
    private GradientViewPortOriginal tableViewPort;

    public ViewPortFlickeringOriginal() {
        tableViewPort = new GradientViewPortOriginal(table);
        viewport = tableViewPort.getViewport();
        viewport.addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                if (tableViewPort.bolStart) {
                    RECT = table.getCellRect(0, 0, true);
                    RECT1 = table.getCellRect(table.getRowCount() - 1, 0, true);
                    Rectangle viewRect = viewport.getViewRect();
                    if (viewRect.intersects(RECT)) {
                        System.out.println("Visible RECT -> " + RECT);
                        tableViewPort.paintBackGround(new Color(250, 150, 150));
                    } else if (viewRect.intersects(RECT1)) {
                        System.out.println("Visible RECT1 -> " + RECT1);
                        tableViewPort.paintBackGround(new Color(150, 250, 150));
                    } else {
                        System.out.println("Visible RECT1 -> ???? ");
                        tableViewPort.paintBackGround(new Color(150, 150, 250));
                    }
                }
            }
        });
        frame.add(tableViewPort);
        frame.setPreferredSize(new Dimension(600, 300));
        frame.pack();
        frame.setLocation(50, 100);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        RepaintManager.setCurrentManager(new RepaintManager() {

            @Override
            public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
                Container con = c.getParent();
                while (con instanceof JComponent) {
                    if (!con.isVisible()) {
                        return;
                    }
                    if (con instanceof GradientViewPortOriginal) {
                        c = (JComponent) con;
                        x = 0;
                        y = 0;
                        w = con.getWidth();
                        h = con.getHeight();
                    }
                    con = con.getParent();
                }
                super.addDirtyRegion(c, x, y, w, h);
            }
        });
        frame.setVisible(true);
        start();
    }

    private void start() {
        timer = new javax.swing.Timer(100, updateCol());
        timer.start();
    }

    public Action updateCol() {
        return new AbstractAction("text load action") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {

                System.out.println("updating row " + (count + 1));
                TableModel model = table.getModel();
                int cols = model.getColumnCount();
                int row = 0;
                for (int j = 0; j < cols; j++) {
                    row = count;
                    table.changeSelection(row, 0, false, false);
                    timer.setDelay(100);
                    Object value = "row " + (count + 1) + " item " + (j + 1);
                    model.setValueAt(value, count, j);
                }
                count++;
                if (count >= table.getRowCount()) {
                    timer.stop();
                    table.changeSelection(0, 0, false, false);
                    java.awt.EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            table.clearSelection();
                            tableViewPort.bolStart = true;
                        }
                    });
                }
            }
        };
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ViewPortFlickeringOriginal viewPortFlickering = new ViewPortFlickeringOriginal();
            }
        });
    }
}

class GradientViewPortOriginal extends JScrollPane {

    private static final long serialVersionUID = 1L;
    private final int h = 50;
    private BufferedImage img = null;
    private BufferedImage shadow = new BufferedImage(1, h, BufferedImage.TYPE_INT_ARGB);
    private JViewport viewPort;
    public boolean bolStart = false;

    public GradientViewPortOriginal(JComponent com) {
        super(com);
        viewPort = this.getViewport();
        viewPort.setScrollMode(JViewport.BLIT_SCROLL_MODE);
        viewPort.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
        viewPort.setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
        paintBackGround(new Color(250, 150, 150));
    }

    public void paintBackGround(Color g) {
        Graphics2D g2 = shadow.createGraphics();
        g2.setPaint(g);
        g2.fillRect(0, 0, 1, h);
        g2.setComposite(AlphaComposite.DstIn);
        g2.setPaint(new GradientPaint(0, 0, new Color(0, 0, 0, 0f), 0, h,
                new Color(0.1f, 0.8f, 0.8f, 0.5f)));
        g2.fillRect(0, 0, 1, h);
        g2.dispose();
    }

    @Override
    public void paint(Graphics g) {
        if (img == null || img.getWidth() != getWidth() || img.getHeight() != getHeight()) {
            img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
        }
        Graphics2D g2 = img.createGraphics();
        super.paint(g2);
        Rectangle bounds = getViewport().getVisibleRect();
        g2.scale(bounds.getWidth(), -1);
        int y = (getColumnHeader() == null) ? 0 : getColumnHeader().getHeight();
        g2.drawImage(shadow, bounds.x, -bounds.y - y - h, null);
        g2.scale(1, -1);
        g2.drawImage(shadow, bounds.x, bounds.y + bounds.height - h + y, null);
        g2.dispose();
        g.drawImage(img, 0, 0, null);
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • How can i get the rectangle or point of a specific table within the panel? if i say getLocation() on the table it just says the x = 0 and y = 0 – 3uPh0riC Jan 21 '14 at 13:15
  • this is non_sence :-), forgot about, for why reason you want to convert dynamic (each JTable can be scrolled direfently, then stays with variable value from JScrollBar) coordinates (100 JTables in JScrollPane) to the parent to JPanel, – mKorbel Jan 21 '14 at 13:34