-1

enter image description hereIm wondering if anyone can help me replicate the below screenshot. im tring to display a counter that will count in increments of 20 up to 100 the will count up 1 on the left hand side number then keep counting in increments and replicate..

enter image description here

eg:000 > 0/0/20      0/1/60
       > 0/0/40      0/1/80
       > 0/0/60      0/2/00
       > 0/0/80      0/2/20
       > 0/1/00      >>>>
       > 0/1/20      0/9/80
       > 0/1/40      1/0/00

etc...

Delish
  • 77
  • 1
  • 12
  • 5
    [What have you tried](http://mattgemmell.com/2008/12/08/what-have-you-tried/) so far and how is it not working? I would assume that you're trying by using a [Swing Timer](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html), right? – Hovercraft Full Of Eels Feb 22 '13 at 17:10
  • i havnt tried anything yet ive it just as a JTextField thats counts on keypress. but now i need that when it gets to a number it increments the next one.. no idea how to even lay it out yet.. – Delish Feb 22 '13 at 17:16
  • 2
    Then you might be premature in coming here. Why not experiment and first try to come up with a solution on your own, and only then if you get stuck, come back with your attempt? – Hovercraft Full Of Eels Feb 22 '13 at 17:17
  • well i have tried quite a few thing jus none get even close so didnt think to mention it.. like i tried counting 5 keypresses then incrmenting the next field but no joy, also tries two JTextfields beside each other but that didnt work either.. – Delish Feb 22 '13 at 17:20
  • Then consider *showing* us what didn't work. It's the best way for us to know exactly where you may be stuck. – Hovercraft Full Of Eels Feb 22 '13 at 17:22

2 Answers2

1

You can do this with a custom SliderUI, shown here, is a JSlider having a VERTICAL orientation. The example calls drawLine () in paintThumb(), but you can use TextLayout, illustrated here, to render the numbers.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 1
    @BenJi see GLassPane or JLayer(Java7),for todays Java GUI only JLayer should be proper solution for this job, everythig else is simulating .... – mKorbel Feb 22 '13 at 22:44
1

This is an incredibly basic example. There is a lot of room for improvement in it's range checking.

enter image description here

The linear scroller is really simple. In the end I used the same basic concept as I did for the circular scroller, simply creating a BufferedImage with all the values marked on it, and based on the value, calculate the appropriate layout position.

The circular scroller took a little longer to bring about. The end result is really rather basic, the trouble is in calculating the under and overflow values.

The circular scroll simple creates a BufferedImage of all the available values. Based on it's display position, we either paint another copy of it before or after it, to give the illusion of flow...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.BoundedRangeModel;
import javax.swing.DefaultBoundedRangeModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;

public class Altimiter {

    public static void main(String[] args) {
        new Altimiter();
    }

    public Altimiter() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private AltPane altPane;

        public TestPane() {

            JButton up = new JButton("+");
            JButton down = new JButton("-");

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            add(up, gbc);
            gbc.gridy++;
            add(down, gbc);

            gbc.gridx++;
            gbc.gridy = 0;
            gbc.gridheight = GridBagConstraints.REMAINDER;

            altPane = new AltPane();
            add(altPane, gbc);

            up.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    altPane.setSpeed(25);
                }
            });
            down.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    altPane.setSpeed(-25);
                }
            });

            altPane.setValue(0);

        }
    }

    public class AltPane extends JPanel {

        private LinearScrollerPane major;
        private CircularScrollerPane minor;
        private int altitude = 0;
        private int direction = 0;
        private Timer timer;

        public AltPane() {
            major = new LinearScrollerPane();
            minor = new CircularScrollerPane();
            major.setOpaque(false);
            minor.setOpaque(false);

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.fill = GridBagConstraints.VERTICAL;
            gbc.weighty = 1; 

            add(major, gbc);
            gbc.gridx++;
            add(minor, gbc);
            setBorder(new LineBorder(Color.BLUE));

            timer = new Timer(1000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    altitude += direction;
                    if (altitude < 0) {
                        ((Timer) e.getSource()).stop();
                        altitude = 0;
                    } else if (altitude > 20000) {
                        ((Timer) e.getSource()).stop();
                        altitude = 20000;
                    }
                    System.out.println("value = " + altitude);
                    setValue(altitude);
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.setInitialDelay(0);
        }

        public void setSpeed(int speed) {
            this.direction = speed;
            timer.start();
        }

        public void setValue(int value) {
            int hnds = value / 100;
            int units = value - (hnds * 100);

            if (units == 0) {
                if (hnds > 0 && direction > 0) {
                    units = 100;
                } else if (hnds > 0 && direction < 0) {
                    units = -1;
                } else {
                    units = 0;
                }
            }

            major.setValue(hnds);
            minor.setValue(units);

            invalidate();
            repaint();
        }

        public int getValue() {
            int ths = major.getValue();
            int hnds = minor.getValue();
            return (ths * 100) + hnds;
        }

        @Override
        public void paint(Graphics g) {
            super.paint(g);
            Insets insets = getInsets();
            int width = getWidth() - (insets.left + insets.top);
            int height = getHeight() - (insets.top + insets.bottom);
            g.setColor(new Color(255, 0, 0, 128));
            int centerY = insets.top + (height / 2);
            g.drawLine(insets.left, centerY, insets.left + width, centerY);
        }
    }

    public class CircularScrollerPane extends JPanel {

        private BufferedImage baseView;
        private BoundedRangeModel model;
        private float startValue = 0;
        private float currentValue = 0;
        private float targetValue = 0;
        private int rowCount = 3;
        private Timer timer;
        private long startTime;
        private int runTime = 1000;

        public CircularScrollerPane() {
            setModel(new DefaultBoundedRangeModel(0, 20, 0, 100));

            timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    long now = System.currentTimeMillis();
                    long diff = now - startTime;
                    if (diff >= runTime) {
                        ((Timer) (e.getSource())).stop();
                        diff = runTime;
                    }
                    float progress = (float) diff / (float) runTime;

                    currentValue = calculateProgress(startValue, targetValue, progress);
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(false);
        }

        public int getValue() {
            return getModel().getValue();
        }

        public void setValue(int value) {
            timer.stop();

            BoundedRangeModel model = getModel();
            if (value < model.getMinimum()) {
                value = model.getMaximum() + (value + 1);
                currentValue += model.getMaximum(); // overflow
            } else if (value > model.getMaximum() - model.getExtent()) {
                value = model.getMinimum() + (value - model.getMaximum());
                currentValue -= model.getMaximum(); // underflow
            }
            startValue = currentValue;
            targetValue = value;

            model.setValue(value);

            startTime = System.currentTimeMillis();
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            FontMetrics fm = getFontMetrics(getFont());
            return fm == null ? super.getPreferredSize() : new Dimension(fm.stringWidth("MMM"), fm.getHeight() * getRowCount());
        }

        public void setRowCount(int value) {
            if (value != rowCount) {
                int old = rowCount;
                rowCount = value;
                invalidate();
                repaint();
                firePropertyChange("rowCount", old, rowCount);
            }
        }

        public int getRowCount() {
            return rowCount;
        }

        public void setModel(BoundedRangeModel value) {
            if (value != null) {
                BoundedRangeModel old = model;
                model = value;
                if (model != null) {
                    currentValue = model.getValue();
                    targetValue = model.getValue();
                } else {
                    currentValue = 0;
                    targetValue = 0;
                }
                baseView = null;
                firePropertyChange("model", old, model);
            }
        }

        public BoundedRangeModel getModel() {
            return model;
        }

        @Override
        public void invalidate() {
            super.invalidate();
            baseView = null;
        }

        public float getViewOffSet(float value) {
            Font font = getFont();
            FontMetrics fm = getFontMetrics(font);
            int rowHeight = fm.getHeight();
            int extent = model.getExtent();
            int min = model.getMinimum();
            int max = model.getMaximum();

            int viewRange = max - min;
            int ticks = viewRange / extent;

            float p = value / (float) viewRange;

            return ((rowHeight * ticks) * p) + ((fm.getAscent() + fm.getDescent()) / 2);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            BufferedImage masterView = getMasterView();
            if (masterView != null) {

                Insets insets = getInsets();
                int width = getWidth() - (insets.left + insets.right);
                int height = getHeight() - (insets.top + insets.bottom);
                int centerY = height / 2;
                FontMetrics fm = g.getFontMetrics();

                int yOffset = centerY - (int) getViewOffSet(currentValue);

                g.drawImage(masterView, insets.left, insets.top + yOffset, this);

                // Heading image...
                if (yOffset > 0) {
                    g.drawImage(masterView, insets.left, insets.top + yOffset - masterView.getHeight(), this);
                }
                // Tailing image...
                if (yOffset + masterView.getHeight() < height) {
                    g.drawImage(masterView, insets.left, insets.top + yOffset + masterView.getHeight(), this);
                }
            }
        }

        protected String pad(int value) {
            StringBuilder sb = new StringBuilder(value);
            sb.ensureCapacity(3);
            sb.append(value);
            while (sb.length() < 3) {
                sb.insert(0, "0");
            }
            return sb.toString();
        }

        protected BufferedImage getMasterView() {
            if (baseView == null) {
                Insets insets = getInsets();
                int width = getWidth() - (insets.left + insets.right);
                int height = getHeight() - (insets.top + insets.bottom);

                BoundedRangeModel model = getModel();

                int extent = model.getExtent();
                int min = model.getMinimum();
                int max = model.getMaximum();

                int viewRange = max - min;
                int ticks = viewRange / extent;

                Font font = getFont();
                FontMetrics fm = getFontMetrics(font);
                baseView = new BufferedImage(width, fm.getHeight() * ticks, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2d = baseView.createGraphics();
                g2d.setFont(font);
                g2d.setColor(Color.BLACK);
                int yPos = 0;
                for (int index = min; index < max; index += extent) {
                    String value = pad(index);
                    g2d.drawString(value, width - fm.stringWidth(value), yPos + fm.getAscent());
                    yPos += fm.getHeight();
                }
            }
            return baseView;
        }
    }

    public class LinearScrollerPane extends JPanel {

        private BufferedImage baseView;
        private BoundedRangeModel model;
        private float startValue = 0;
        private float currentValue = 0;
        private float targetValue = 0;
        private int rowCount = 3;
        private Timer timer;
        private long startTime;
        private int runTime = 1000;

        public LinearScrollerPane() {

            Font font = UIManager.getFont("Label.font");
            setFont(font.deriveFont(Font.BOLD, font.getSize() + 4));
            setModel(new DefaultBoundedRangeModel(0, 0, 0, 20));

            timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    long now = System.currentTimeMillis();
                    long diff = now - startTime;
                    if (diff >= runTime) {
                        ((Timer) (e.getSource())).stop();
                        diff = runTime;
                    }
                    float progress = (float) diff / (float) runTime;

                    currentValue = calculateProgress(startValue, targetValue, progress);
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(false);
        }

        public int getValue() {
            return getModel().getValue();
        }

        public void setValue(int value) {
            timer.stop();

            BoundedRangeModel model = getModel();
            if (value < model.getMinimum()) {
                value = model.getMinimum();
            } else if (value > model.getMaximum() - model.getExtent()) {
                value = model.getMaximum() - model.getExtent();
            }
            startValue = currentValue;
            targetValue = value;

            model.setValue(value);

            startTime = System.currentTimeMillis();
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            FontMetrics fm = getFontMetrics(getFont());
            return fm == null ? super.getPreferredSize() : new Dimension(fm.stringWidth("MM"), fm.getHeight() * getRowCount());
        }

        public void setRowCount(int value) {
            if (value != rowCount) {
                int old = rowCount;
                rowCount = value;
                invalidate();
                repaint();
                firePropertyChange("rowCount", old, rowCount);
            }
        }

        public int getRowCount() {
            return rowCount;
        }

        public void setModel(BoundedRangeModel value) {
            if (value != null) {
                BoundedRangeModel old = model;
                model = value;
                if (model != null) {
                    currentValue = model.getValue();
                    targetValue = model.getValue();
                } else {
                    currentValue = 0;
                    targetValue = 0;
                }
                baseView = null;
                firePropertyChange("model", old, model);
            }
        }

        public BoundedRangeModel getModel() {
            return model;
        }

        @Override
        public void invalidate() {
            super.invalidate();
            baseView = null;
        }

        public float getViewOffSet(float value) {
            Font font = getFont();
            FontMetrics fm = getFontMetrics(font);
            int rowHeight = fm.getHeight();
            int min = model.getMinimum();
            int max = model.getMaximum();

            int viewRange = max - min;
            int ticks = getTicks();

            float p = value / (float) viewRange;

            return ((rowHeight * ticks) * p) + ((fm.getAscent() + fm.getDescent()) / 2);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            BufferedImage masterView = getMasterView();
            if (masterView != null) {

                Insets insets = getInsets();
                int width = getWidth() - (insets.left + insets.right);
                int height = getHeight() - (insets.top + insets.bottom);
                int centerY = height / 2;
                FontMetrics fm = g.getFontMetrics();

                int yOffset = centerY - (int) getViewOffSet(currentValue);

                g.drawImage(masterView, insets.left, insets.top + yOffset, this);
            }
        }

        protected String pad(int value) {
            StringBuilder sb = new StringBuilder(value);
            sb.ensureCapacity(3);
            sb.append(value);
            while (sb.length() < 3) {
                sb.insert(0, "0");
            }
            return sb.toString();
        }

        protected int getTicks() {
            BoundedRangeModel model = getModel();

            int extent = model.getExtent();
            int min = model.getMinimum();
            int max = model.getMaximum();
            int viewRange = max - min;
            int ticks = viewRange;
            if (extent > 0) {
                ticks = viewRange / extent;
            }

            return ticks;
        }

        protected BufferedImage getMasterView() {
            if (baseView == null) {
                Insets insets = getInsets();
                int width = getWidth() - (insets.left + insets.right);
                int height = getHeight() - (insets.top + insets.bottom);

                BoundedRangeModel model = getModel();

                int extent = model.getExtent();
                int min = model.getMinimum();
                int max = model.getMaximum();

                int ticks = getTicks() + 1;

                Font font = getFont();
                FontMetrics fm = getFontMetrics(font);
                baseView = new BufferedImage(width, fm.getHeight() * ticks, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2d = baseView.createGraphics();
                g2d.setFont(font);
                g2d.setColor(Color.BLACK);
                int yPos = 0;
                for (int index = min; index < max + 1; index += Math.max(1, extent)) {
                    String value = String.valueOf(index);
                    g2d.drawString(value, width - fm.stringWidth(value), yPos + fm.getAscent());
                    yPos += fm.getHeight();
                }
                g2d.dispose();
            }
            return baseView;
        }
    }

    public static float calculateProgress(float startValue, float endValue, double fraction) {
        float value = 0;
        float distance = endValue - startValue;
        value = (float) (distance * fraction);
        value += startValue;
        return value;
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • 1
    I have a bunch of other ideas that might give better results, but finding the time to play is an issue – MadProgrammer Feb 26 '13 at 19:04
  • any idea how to put it in a JTextView? (where it says altitude on screenshot) ha.. no matter what i try seems to only display as a border :( will edit original post to include screenshot.. @MadProgrammer – Delish Feb 27 '13 at 16:28