Pregunta

Estoy usando un JSlider para mostrar el progreso en mi solicitud, por lo que se actualiza como un cierto proceso calcula.

Quiero que un usuario sea capaz de arrastrar el dedo pulgar hacia atrás para una marca de verificación en el pasado, pero cuando esto sucede, quiero que el indicador de progreso a permanecer en su posición actual.

// A dismal attempt at drawing the situation
Progress: ---------
Thumb:            |

// User drags backwards.  What I have:
Progress: ---
Thumb:       |

// What I want instead:
Progress: ---------
Thumb:       |

¿Puede cualquier persona ofrecer una guía sobre cómo lograr mejor esto? Gracias de antemano por toda la ayuda!

¿Fue útil?

Solución 2

lo he descubierto. Extendí JSlider para realizar un seguimiento del progreso por separado de la posición del pulgar actual, y luego hizo caso omiso método paintTrack del MetalSliderUI dibujar llenar la pista a la posición que quiera.

Aquí está la solución, simplificada las partes importantes.

La nueva barra de progreso:

public class ProgressSlider extends JSlider {
    protected int progress;
    private static final String uiClassID = "ProgressSliderUI";

    public ProgressSlider() {
        progress = 0;
        putClientProperty("JSlider.isFilled", Boolean.TRUE);
        updateUI();
    }
    public void updateUI() {
        setUI(new ProgressSliderUI(this));
    }
    public String getUIClassID() {
        return uiClassID;
    }

    public int getProgress() {
        return this.progress;
    }

    public void setProgress(int value) {
        if (value < this.getMinimum()) {
            this.progress = this.getMinimum();
        }
        else if (value > this.getMaximum()) {
            this.progress = this.getMaximum();
        }
        else {
            this.progress = value;
        }
    }
}

La nueva interfaz de usuario: Tenga en cuenta, que sólo había 2 líneas añadidas al método paintTrack () en la clase de interfaz de usuario, inmediatamente después del comentario diciendo por ejemplo.

public class ProgressSliderUI extends MetalSliderUI {

    public ProgressSliderUI() {
        super();
    }

    public ProgressSliderUI(JSlider b) {
    }

    @Override
    public void paintTrack(Graphics g) {
        Color trackColor = !slider.isEnabled() ? MetalLookAndFeel
                .getControlShadow() : Color.blue;

        boolean leftToRight = true;

        g.translate(trackRect.x, trackRect.y);

        int trackLeft = 0;
        int trackTop = 0;
        int trackRight = 0;
        int trackBottom = 0;

        // Draw the track
        if (slider.getOrientation() == JSlider.HORIZONTAL) {
            trackBottom = (trackRect.height - 1) - getThumbOverhang();
            trackTop = trackBottom - (getTrackWidth() - 1);
            trackRight = trackRect.width - 1;
        }
        else {
            if (leftToRight) {
                trackLeft = (trackRect.width - getThumbOverhang())
                        - getTrackWidth();
                trackRight = (trackRect.width - getThumbOverhang()) - 1;
            }
            else {
                trackLeft = getThumbOverhang();
                trackRight = getThumbOverhang() + getTrackWidth() - 1;
            }
            trackBottom = trackRect.height - 1;
        }

        if (slider.isEnabled()) {
            g.setColor(MetalLookAndFeel.getControlDarkShadow());
            g.drawRect(trackLeft, trackTop, (trackRight - trackLeft) - 1, 
                                           (trackBottom - trackTop) - 1);

            g.setColor(MetalLookAndFeel.getControlHighlight());
            g.drawLine(trackLeft + 1, trackBottom, trackRight, trackBottom);
            g.drawLine(trackRight, trackTop + 1, trackRight, trackBottom);

            g.setColor(MetalLookAndFeel.getControlShadow());
            g.drawLine(trackLeft + 1, trackTop + 1, 
                                            trackRight - 2, trackTop + 1);
            g.drawLine(trackLeft + 1, trackTop + 1, trackLeft + 1, 
                                                          trackBottom - 2);
        }
        else {
            g.setColor(MetalLookAndFeel.getControlShadow());
            g.drawRect(trackLeft, trackTop, (trackRight - trackLeft) - 1, 
                                            (trackBottom - trackTop) - 1);
        }

        // Draw the fill
        if (filledSlider) {
            int middleOfThumb = 0;
            int fillTop = 0;
            int fillLeft = 0;
            int fillBottom = 0;
            int fillRight = 0;

            if (slider.getOrientation() == JSlider.HORIZONTAL) {
                middleOfThumb = thumbRect.x + (thumbRect.width / 2);
                middleOfThumb -= trackRect.x; // To compensate for the
                // g.translate()
                fillTop = !slider.isEnabled() ? trackTop : trackTop + 1;
                fillBottom = !slider.isEnabled() ? trackBottom - 1
                        : trackBottom - 2;

                if (!drawInverted()) {
                    fillLeft = !slider.isEnabled() ? trackLeft : trackLeft + 1;

                    // THIS IS THE CHANGE OF NOTE:
                    // Fills the progress with the value from the custom slider
                    fillRight = xPositionForValue(((ProgressSlider) slider)
                            .getProgress());
                    fillRight -= trackRect.x;
                }
                else {
                    fillLeft = middleOfThumb;
                    fillRight = !slider.isEnabled() ? trackRight - 1
                            : trackRight - 2;
                }
            }
            else {
                middleOfThumb = thumbRect.y + (thumbRect.height / 2);
                middleOfThumb -= trackRect.y; // To compensate for the
                // g.translate()
                fillLeft = !slider.isEnabled() ? trackLeft : trackLeft + 1;
                fillRight = !slider.isEnabled() ? trackRight - 1
                        : trackRight - 2;

                if (!drawInverted()) {
                    fillTop = middleOfThumb;
                    fillBottom = !slider.isEnabled() ? trackBottom - 1
                            : trackBottom - 2;
                }
                else {
                    fillTop = !slider.isEnabled() ? trackTop : trackTop + 1;
                    fillBottom = middleOfThumb;
                }
            }

            if (slider.isEnabled()) {
                g.setColor(slider.getBackground());
                g.drawLine(fillLeft, fillTop, fillRight, fillTop);
                g.drawLine(fillLeft, fillTop, fillLeft, fillBottom);

                g.setColor(trackColor);
                g.fillRect(fillLeft + 1, fillTop + 1, fillRight
                                - fillLeft, fillBottom - fillTop);
            }
            else {
                g.setColor(MetalLookAndFeel.getControlShadow());
                g.fillRect(fillLeft, fillTop, fillRight - fillLeft, 
                                      trackBottom - trackTop);
            }
        }

        g.translate(-trackRect.x, -trackRect.y);
    }

}

Y para el conductor para probarlo:

public class ProgressExample extends JFrame
{
    public ProgressExample()
    {
        super("Progress Example");

        ProgressSlider mSlider = new ProgressSlider();
        mSlider.setMinimum(0);
        mSlider.setMaximum(100);
        mSlider.setValue(20);
        mSlider.setProgress(50);

        getContentPane().setLayout(new FlowLayout());
        getContentPane().add(slider);
        getContentPane().add(mSlider);
    }
    public static void main(String args[])
    {
        ProgressExample f = new ProgressExample();
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e)
            {
                System.exit(0);
            }
        });
        f.setSize(300, 80);
        f.show();
    }
}

Otros consejos

Ah, ya veo lo que quiere decir. Desafortunadamente, no hay manera de hacerlo.

La 'barra azul" no es realmente parte de JSlider, es parte de la LAF metal. Es sólo la forma en que la LAF metal eligió pintar el componente. Si lo intenta con otro LAF no recibe la barra en todos.

Usted necesitará un par de JProgressBar y una JSlider para conseguir lo que desea.

Aquí hay un punto de partida. Tendrá que retocarlo para conseguir que se ve bien

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.event.ChangeListener;

public class ProgressSlider extends javax.swing.JPanel
{
    private JProgressBar progressBar;
    private JSlider slider;
    public ProgressSlider() {
        this(0, 100);
    }
    public ProgressSlider(int min, int max) {
        setLayout(new GridBagLayout());

        GridBagConstraints gbc;
        gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        slider = new JSlider(min, max, min);
        progressBar = new JProgressBar(min, max);
        add(slider, gbc);
        add(progressBar, gbc);
    }
    public void setValue(int n) {
        boolean adjSlider = slider.getValue() == progressBar.getValue();
        progressBar.setValue(n);
        if (adjSlider)
            slider.setValue(n);
    }
    public int getValue() {
        return progressBar.getValue();
    }
    public int getSliderValue() {
        return slider.getValue();
    }
    public void syncSlider() {
        slider.setValue(progressBar.getValue());
    }
    public void addChangeListener(ChangeListener l) {
        slider.addChangeListener(l);
    }
    public void removeChangeListener(ChangeListener l) {
        slider.removeChangeListener(l);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame jf = new JFrame();
                jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                final ProgressSlider ps = new ProgressSlider();
                final JTextField tf = new JTextField(4);
                final JButton jb = new JButton(new AbstractAction("Set") {
                    public void actionPerformed(ActionEvent e) {
                        ps.setValue(Integer.parseInt(tf.getText()));
                    }});
                JPanel jp = new JPanel();
                jp.add(tf);
                jp.add(jb);
                jf.getContentPane().add(ps, BorderLayout.CENTER);
                jf.getContentPane().add(jp, BorderLayout.SOUTH);
                jf.pack();
                jf.setVisible(true);
            }
        });
    }
}

Bueno, yo no veo cómo esto es posible. Tendrá que personalizar la interfaz de usuario de control deslizante y cambiar el modelo, ya que no necesita almacenar dos piezas de información del modelo, el "valor de pista" y el "valor del pulgar".

Si quieres una gran corte, entonces se pinta dos controles deslizantes en la parte superior de uno al otro. La corredera inferior sería que el valor de la pista y la parte superior sería que el valor pulgar.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.metal.*;

public class SliderTest extends JFrame
{
    public SliderTest()
    {
        JSlider bottom = createSlider();
        bottom.setUI( new MySliderUI1() );

        JSlider top = createSlider();
        top.setUI( new MySliderUI2() );
        top.setOpaque(false);

        JPanel panel = new JPanel();
        panel.setLayout( new OverlapLayout() );
        panel.add( bottom );
        panel.add( top );

        getContentPane().add( panel );
    }

    private JSlider createSlider()
    {
        JSlider slider = new JSlider(2, 50);
        slider.createStandardLabels(10, 5);
        slider.setMajorTickSpacing(10);
        slider.setPaintTicks(true);
        slider.setPaintLabels(true);
        slider.setValue(20);

        return slider;
    }

    class MySliderUI1 extends MetalSliderUI
    {
        public void paintThumb(Graphics g) {}
    }

    class MySliderUI2 extends MetalSliderUI
    {
        public void paintTrack(Graphics g) {}
    }

    public static void main(String[] args)
    {
        JFrame frame = new SliderTest();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
     }
}

También tendrá la superposición Disposición . ¿Cómo usted los mantiene en sincronía sería de usted. La solución tiene muchos defectos, pero le puede dar algunas ideas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top