001package jmri.jmrix.can.cbus.swing.modules; 002 003import java.awt.*; 004import java.util.TimerTask; 005 006import javax.swing.*; 007import javax.swing.border.*; 008import javax.swing.event.ChangeEvent; 009import javax.swing.event.ChangeListener; 010 011import jmri.util.TimerUtil; 012 013 014/** 015 * JSlider with a titled border 016 * 017 * @author Andrew Crosland Copyright (C) 2022 018 */ 019public class TitledSlider extends JPanel implements ChangeListener { 020 021 protected JSlider tSlide; 022 protected int _index; 023 protected String _title; 024 protected UpdateNV _update; 025 026 /** 027 * Construct a new titledSlider 028 * 029 * @param title to be displayed 030 * @param index of the associated NV 031 * @param update callback funtion to apply new value 032 */ 033 public TitledSlider(String title, int index, UpdateNV update) { 034 super(); 035 _title = title; 036 _index = index; 037 _update = update; 038 tSlide = new JSlider(); 039 } 040 041 /** 042 * Initialise the slider 043 * 044 * @param init Initial value 045 * @param min Minimum value 046 * @param max Maximum value 047 */ 048 public void init(int min, int max, int init) { 049 GridLayout grid = new GridLayout(1, 1); 050 setLayout(grid); 051 052 Border border = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); 053 TitledBorder titled = BorderFactory.createTitledBorder(border, _title); 054 setBorder(titled); 055 056 tSlide.setMinimum(min); 057 tSlide.setMaximum(max); 058 tSlide.setValue(init); 059 tSlide.addChangeListener(this); 060 061 add(tSlide); 062 } 063 064 /** 065 * Set slider value 066 * 067 * Only do this if value has actually changed, otherwise we can trigger 068 * an endless round of updating to the table and the gui. 069 * 070 * @param v value 071 */ 072 public void setValue(int v) { 073 if (v != tSlide.getValue()) { 074 tSlide.setValue(v); 075 } 076 } 077 078 /** 079 * Get slider value 080 * 081 * @return slider value 082 */ 083 public int getValue() { 084 return tSlide.getValue(); 085 } 086 087 /** 088 * Set the tool tip 089 * 090 * @param tt tooltip text 091 */ 092 public void setToolTip(String tt) { 093 tSlide.setToolTipText(tt); 094 } 095 096 /** 097 * Call back with updated value 098 * 099 * We restrict the frequency of updates, with a timer, whilst the slider 100 * is adjusting to, prevent CBUS replies from earlier updates looking 101 * like a new value change and triggering another update as this can 102 * lead to an endless round of updates. 103 * 104 * @param e the slider change event 105 */ 106 @Override 107 public void stateChanged(ChangeEvent e) { 108 JSlider source = (JSlider)e.getSource(); 109 if (!source.getValueIsAdjusting()) { 110// log.debug("TitledSlider.stateChanged() finished adjusting - final update"); 111 _update.setNewVal(_index); 112 if (timerTask != null) { 113 timerTask.cancel(); 114 timerTask = null; 115 } 116 } else if (timerTask == null) { 117// log.debug("TitledSlider.stateChanged() update"); 118 _update.setNewVal(_index); 119 startTimer(); 120 } 121 } 122 123 /** 124 ** The preferred width on the panel must consider the width of the text 125 ** used on the TitledBorder 126 * 127 * from <a href=https://stackoverflow.com/questions/43425939/how-to-get-the-titledborders-title-to-display-properly-in-the-gui></a> 128 */ 129 @Override 130 public Dimension getPreferredSize() { 131 132 Dimension preferredSize = super.getPreferredSize(); 133 134 Border border = getBorder(); 135 int borderWidth = 0; 136 137 if (border instanceof TitledBorder) { 138 Insets insets = getInsets(); 139 TitledBorder titledBorder = (TitledBorder)border; 140 borderWidth = titledBorder.getMinimumSize(this).width + insets.left + insets.right; 141 } 142 143 int preferredWidth = Math.max(preferredSize.width, borderWidth); 144 145 return new Dimension(preferredWidth, preferredSize.height); 146 } 147 148 private TimerTask timerTask; 149 150 /** 151 * Start timer for update throttling 152 */ 153 private void startTimer() { 154 timerTask = new TimerTask() { 155 @Override 156 public void run() { 157 timerTask = null; 158 } 159 }; 160 TimerUtil.schedule(timerTask, 100); 161 } 162 163// private final static Logger log = LoggerFactory.getLogger(TitledSlider.class); 164 165}