2009-09-23 4 views
2

J'utilise un JSlider pour montrer les progrès dans mon application, de sorte qu'il se met à jour au fur et à mesure qu'un certain processus est calculé.Comment dissocier un indicateur de progression d'un JSlider de son pouce?

Je veux qu'un utilisateur puisse faire glisser le pouce vers l'arrière jusqu'à une marque de graduation dans le passé, mais lorsque cela se produit, je veux que l'indicateur de progression reste à sa position actuelle.

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

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

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

Quelqu'un peut-il offrir des conseils sur la meilleure façon d'y parvenir? Merci d'avance pour toute aide!

+0

Vous devrez poster un exemple de code. J'utilise beaucoup JSlider et je n'ai jamais vu la taille de la piste changer en réponse au déplacement du curseur. En tant que WAG, la valeur est en quelque sorte réinjectée dans la taille du composant et ce que vous voyez est le composant qui change la taille. –

+0

Peut-être que je l'ai mal écrit alors. Je veux vraiment l'indicateur de progression (la ligne bleue qui se développe lorsque le pouce descend le composant). Qu'est-ce que c'est vraiment appelé? – Cuga

+0

Quelle est la différence entre ce que vous avez et ce que vous voulez? Ils me ressemblent. –

Répondre

1

Je l'ai compris, j'ai étendu JSlider pour suivre la progression à partir de la position actuelle du curseur, puis surpasser la méthode paintTrack de MetalSliderUI pour dessiner la piste à la position souhaitée.

Voici la solution, dépouillée des parties importantes.

La nouvelle barre de progression:

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 nouvelle interface utilisateur: Remarque, il n'y avait que 2 lignes ajoutées à la méthode paintTrack() dans la classe de l'interface utilisateur, immédiatement après le commentaire disant que tel.

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); 
    } 

} 

Et pour le conducteur pour le tester:

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(); 
    } 
} 
0

Eh bien, je ne vois pas comment cela est possible. Vous devrez personnaliser l'interface utilisateur du curseur et modifier le modèle car vous n'avez pas besoin de stocker deux informations sur le modèle, la «valeur de suivi» et la «valeur du pouce».

Si vous voulez un gros hack, vous devez peindre deux curseurs les uns sur les autres. Le curseur du bas serait pour la valeur de la piste et le haut serait pour la valeur du pouce.

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); 
    } 
} 

Vous aurez également besoin de Overlap Layout. La façon dont vous les synchronisez dépend de vous. La solution a de nombreux défauts, mais cela peut vous donner quelques idées.

+0

Je suis allé avec une solution proche de ce dont vous avez parlé pour la première fois - étendre JSlider pour suivre la progression et remplacer le MetalSliderUI pour peindre la piste au point que je voulais. Merci pour l'aide. – Cuga

1

Ah, je vois ce que vous voulez dire. Malheureusement, il n'y a aucun moyen de le faire.

La «barre bleue» ne fait pas vraiment partie de JSlider, elle fait partie de la Metal LAF, c'est comme ça que la Metal LAF a choisi de peindre le composant, si vous l'essayez avec une autre LAF du tout.

vous aurez besoin de coupler un JProgressBar et un JSlider pour obtenir ce que vous voulez.

est ici un point de départ. vous aurez besoin de ruser pour obtenir à regarder à droite

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); 
      } 
     }); 
    } 
} 
+0

Je vois ce que vous disiez à propos du Metal LAF. J'ai décidé d'étendre sa méthode paintTrack() par la solution que j'ai postée. Merci pour l'aide. – Cuga

Questions connexes