{"id":1081,"date":"2021-01-13T15:42:43","date_gmt":"2021-01-13T15:42:43","guid":{"rendered":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/?page_id=1081"},"modified":"2021-01-13T16:21:30","modified_gmt":"2021-01-13T16:21:30","slug":"sliders-spinners","status":"publish","type":"page","link":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/course-topics\/swing-gui-components\/sliders-spinners\/","title":{"rendered":"Sliders &#038; Spinners"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_85 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a6d49b539047\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a6d49b539047\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/course-topics\/swing-gui-components\/sliders-spinners\/#Sliders\" >Sliders<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/course-topics\/swing-gui-components\/sliders-spinners\/#Spinners\" >Spinners<\/a><\/li><\/ul><\/nav><\/div>\n\n<p class=\"wp-block-paragraph\">Java Swing has introduced some new Swing components:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong><em>Sliders<\/em><\/strong>, and<\/li><li><strong><em>Spinners<\/em><\/strong><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Here are some details&#8230;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Sliders\"><\/span>Sliders<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A&nbsp;<em><strong>slider<\/strong><\/em>&nbsp;control allows a user to choose from a continuum of values between a minimum and maximum value.&nbsp; Sliders were introduced in Java 1.4, and behave somewhat like scrollbars, except that they can be visually configured in a more pleasing way than scrollbars.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s an example of the use and configuration of a slider control:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; highlight: [7,26,27,28,39,40]; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingExamples;\n\nimport java.awt.BorderLayout;\nimport java.awt.Container;\n\nimport javax.swing.JFrame;\nimport javax.swing.JSlider;\nimport javax.swing.SwingConstants;\n\n\/**\n * A JFrame class to demonstrate JSlider usage.\n *\/\nclass SlidersFrame extends JFrame\n{\n  public SlidersFrame()\n  {\n    setTitle(&quot;Sliders&quot;);\n    setDefaultCloseOperation(EXIT_ON_CLOSE);\n    Container panel = getContentPane();\n    panel.setLayout( new BorderLayout() );\n    \n    panel.add(\n        new TitlePanel(&quot;Slider Configuration&quot;), \n                       BorderLayout.NORTH);\n    \n    JSlider slider = new JSlider();\n    slider.setMajorTickSpacing(20);\n    slider.setMinorTickSpacing(5);\n    panel.add(\n        new SliderPanel(slider), BorderLayout.CENTER);\n    \n    panel.add(\n        new FeelPanel(SwingConstants.VERTICAL), \n                      BorderLayout.WEST);\n    \n    ValuePanel valuePanel = new ValuePanel();\n    panel.add(valuePanel, BorderLayout.EAST);\n    valuePanel.setValue(slider);\n    \/\/ Set up change listener so we can see the value\n    slider.addChangeListener(valuePanel);\n    \n    ControlPanel controlPanel = new ControlPanel(slider);\n    panel.add(controlPanel, BorderLayout.SOUTH);\n    \n    pack();\n  }\n}\n\npublic class Sliders\n{\n  public static void main(String&#x5B;] args)\n  {\n    JFrame frame = new SlidersFrame();\n    frame.setVisible(true);\n  }\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingExamples;\n\nimport java.awt.Color;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.SwingConstants;\n\n\/**\n * A panel to display a title string\n *\/\npublic class TitlePanel extends JPanel\n{\n  public TitlePanel(String title)\n  {\n    JLabel label = \n        new JLabel(title,\n                   SwingConstants.CENTER);\n    label.setForeground(Color.BLUE);\n    add(label);\n  }\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; highlight: [8,21,22,23,27]; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingExamples;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\n\nimport javax.swing.BorderFactory;\nimport javax.swing.JPanel;\nimport javax.swing.JSlider;\n\n\/**\n * A panel to display a JSlider component\n *\/\npublic class SliderPanel extends JPanel\n{\n  public SliderPanel(JSlider slider)\n  {\n    m_slider = slider;\n    setBackground(Color.WHITE);\n    setBorder(\n        BorderFactory.createTitledBorder(&quot;Slider:&quot;) );\n    add(m_slider);\n    m_slider.setBorder(\n        BorderFactory.createLineBorder(Color.BLUE));\n  }\n  \n  \/\/\/\/\/\/ Private data \/\/\/\/\/\n  private JSlider m_slider;\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; highlight: [12,26,27,28,29,30,31,32,33,34,35]; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingExamples;\n\nimport javax.swing.BorderFactory;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.JSlider;\nimport javax.swing.SwingConstants;\nimport javax.swing.event.ChangeEvent;\nimport javax.swing.event.ChangeListener;\n\npublic class ValuePanel extends JPanel\n    implements ChangeListener\n{\n  public ValuePanel()\n  {\n    setBorder(\n        BorderFactory.createCompoundBorder(\n        BorderFactory.createEmptyBorder(0, 5, 0, 5),\n        BorderFactory.createTitledBorder(&quot;Value:&quot;)\n        ) );\n    JPanel valueContentsPanel = new JPanel();\n    add(valueContentsPanel);\n    valueContentsPanel.add(m_valueLabel);\n  }\n  \n  public void setValue(JSlider slider)\n  {\n    m_valueLabel.setText(&quot;&quot; + slider.getValue());\n  }\n\n  public void stateChanged(ChangeEvent event)\n  {\n    JSlider slider = (JSlider)event.getSource();\n    setValue(slider);\n  }\n  \n  \/\/\/\/ Private data \/\/\/\/\n  \n  \/\/ A label that shows the current value of the slider\n  private JLabel m_valueLabel =\n      new JLabel(&quot;&quot;, SwingConstants.CENTER);\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; highlight: [20,30,31,32,33,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,131,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,261,262,266,270,290,294]; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingExamples;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.FlowLayout;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.util.Dictionary;\nimport java.util.Hashtable;\n\nimport javax.swing.BorderFactory;\nimport javax.swing.ButtonGroup;\nimport javax.swing.ImageIcon;\nimport javax.swing.JCheckBox;\nimport javax.swing.JFrame;\nimport javax.swing.JLabel;\n\nimport javax.swing.JPanel;\nimport javax.swing.JRadioButton;\nimport javax.swing.JSlider;\nimport javax.swing.SwingUtilities;\n\n\/**\n * A control panel used to configure the layout\n * and properties of a slider component.\n *\/\npublic class ControlPanel extends JPanel\n    implements ActionListener\n{\n  public ControlPanel(JSlider slider)\n  {\n    m_slider = slider;  \/\/ The slider being configured\n    loadImages();       \/\/ Load the icon images\n    \n    setLayout( new BorderLayout() );\n    setBorder(\n        BorderFactory.createTitledBorder(&quot;Configure:&quot;) );\n    \n    \/\/ Create a panel to contain the first set of checkboxes\n    JPanel checkboxPanel = new JPanel();\n    add(checkboxPanel, BorderLayout.NORTH);\n    \/\/ Add the checkbox controls to the checkbox panel\n    checkboxPanel.add(m_ticks);\n    checkboxPanel.add(m_snap);\n    checkboxPanel.add(m_track);\n    checkboxPanel.add(m_inverted);\n    \/\/ Create a panel to contain the orientation buttons\n    JPanel orientationPanel = new JPanel(\n        new FlowLayout(FlowLayout.LEFT) );\n    add(orientationPanel, BorderLayout.CENTER);\n    JPanel orientationButtonsPanel = new JPanel();\n    orientationPanel.add(orientationButtonsPanel);\n    orientationButtonsPanel.setBorder(\n        BorderFactory.createTitledBorder(&quot;Orientation:&quot;) );\n    \/\/ Add the orientation radio buttons to the inner\n    \/\/ panel, adding action listeners as we go.\n    ActionListener orientationListener =\n        new OrientationHandler();\n    for (JRadioButton button : m_orientationButtons)\n    {\n      orientationButtonsPanel.add(button);\n      button.addActionListener(orientationListener);\n    }\n    \n    \/\/ Create a panel to contain the label-related stuff\n    JPanel labelPanel = new JPanel();\n    add(labelPanel, BorderLayout.SOUTH);\n    \/\/ Add the Show labels checkbox to the label panel\n    labelPanel.add(m_labels);\n    \n    \/\/ Create a panel to hold the label radio buttons\n    \/\/ and add it to the control panel.\n    JPanel labelButtonPanel = new JPanel();\n    labelButtonPanel.setBorder(\n        BorderFactory.createTitledBorder(&quot;Label Type:&quot;)\n        );\n    labelPanel.add(labelButtonPanel, BorderLayout.SOUTH);\n    \/\/ Add the radio buttons to the panel, adding\n    \/\/ action listeners as we go.\n    ActionListener labelButtonListener =\n        new LabelTypeActionHandler();\n    for (JRadioButton button : m_labelButtons)\n    {\n      labelButtonPanel.add(button);\n      button.addActionListener(labelButtonListener);\n    }\n  }\n  \n  \/\/ Required by ActionListener\n  \/\/ This handles only the checkbox actions.\n  public void actionPerformed(ActionEvent event)\n  {\n    JCheckBox box = (JCheckBox) event.getSource();\n    if (box == m_ticks)\n    {\n      m_slider.setPaintTicks(\n          m_ticks.isSelected() );\n    }\n    else if (box == m_snap)\n    {\n      m_slider.setSnapToTicks(\n          m_snap.isSelected() );\n    }\n    else if (box == m_track)\n    {\n      m_slider.setPaintTrack(\n          m_track.isSelected() );\n    }\n    else if (box == m_inverted)\n    {\n      m_slider.setInverted(\n          m_inverted.isSelected() );\n    }\n    else if (box == m_labels)\n    {\n      m_slider.setPaintLabels(\n          m_labels.isSelected() );\n    }\n    \n    repaintFrame();\n  }\n  \n  private void repaintFrame()\n  {\n    \/\/ Cause the frame to be repainted and resized\n    SwingUtilities.getWindowAncestor(this).pack();    \n  }\n  \n  \/\/\/\/\/ Private data \/\/\/\/\/\n  \n  private JSlider m_slider;  \/\/ The slider being configured.\n  \n  \/\/ Checkbox controls\n  private JCheckBox m_ticks = new JCheckBox(&quot;Show Ticks&quot;);\n  private JCheckBox m_snap = new JCheckBox(&quot;Snap to ticks&quot;);\n  private JCheckBox m_track = new JCheckBox(&quot;Show Track&quot;, true);\n  private JCheckBox m_inverted = new JCheckBox(&quot;Inverted&quot;);\n  \n  \/\/ Orientation radio buttons\n  private ButtonGroup m_orientationGroup = new ButtonGroup();\n  private static final String \n      HORIZONTAL = &quot;Horizontal&quot;,\n      VERTICAL   = &quot;Vertical&quot;;\n  private static final String&#x5B;] ORIENTATION_ACTIONS =\n  {\n    HORIZONTAL, VERTICAL\n  };\n  private JRadioButton&#x5B;] m_orientationButtons =\n  {\n    new JRadioButton(HORIZONTAL, true),\n    new JRadioButton(VERTICAL)\n  };\n  \/\/ Add radio buttons to button group\n  {\n    int index = 0;\n    for (JRadioButton button : m_orientationButtons)\n    {\n      m_orientationGroup.add(button);\n      String command = ORIENTATION_ACTIONS&#x5B;index++];\n      button.setActionCommand(command);\n    }\n  }\n  \n  \/\/ Labels checkbox\n  private JCheckBox m_labels = new JCheckBox(&quot;Show Labels&quot;);\n  \n  \/\/ Add listeners to checkbox controls\n  {\n    m_ticks.addActionListener(this);\n    m_snap.addActionListener(this);\n    m_track.addActionListener(this);\n    m_inverted.addActionListener(this);\n    m_labels.addActionListener(this);\n  }\n  \n  \/\/ Radio button controls\n  private ButtonGroup m_labelsGroup = new ButtonGroup();\n  private static final String\n      DEFAULT = &quot;Default&quot;,\n      CUSTOM  = &quot;Custom&quot;,\n      ICONS   = &quot;Icons&quot;;\n  private static final String&#x5B;] LABEL_COMMANDS =\n  {\n    DEFAULT, CUSTOM, ICONS\n  };\n  private JRadioButton&#x5B;] m_labelButtons =\n  {\n    new JRadioButton(&quot;Default&quot;, true),\n    new JRadioButton(&quot;Custom (A,B,C...)&quot;),\n    new JRadioButton(&quot;Icons&quot;)\n  };\n  \/\/ Add radio buttons to button group\n  {\n    int index = 0;\n    for (JRadioButton button : m_labelButtons)\n    {\n      m_labelsGroup.add(button);\n      String command = LABEL_COMMANDS&#x5B;index++];\n      button.setActionCommand(command);\n    }\n  }\n  \n  \/\/\/\/\/ Labels for customizing the slider \/\/\/\/\/\n  \n  \/\/ A dictionary to hold custom JLabels for the apha labels\n  private Dictionary&lt;Integer, JLabel&gt; m_labelTable =\n      new Hashtable&lt;Integer, JLabel&gt;();\n  \/\/ Initialize the label table\n  {\n    m_labelTable.put(0, new JLabel(&quot;A&quot;));\n    m_labelTable.put(20, new JLabel(&quot;B&quot;));\n    m_labelTable.put(40, new JLabel(&quot;C&quot;));\n    m_labelTable.put(60, new JLabel(&quot;D&quot;));\n    m_labelTable.put(80, new JLabel(&quot;E&quot;));\n    m_labelTable.put(100, new JLabel(&quot;F&quot;));\n  };\n  \n  \/\/ A dictionary to hold JLabels for the icon labels\n  private Dictionary&lt;Integer, JLabel&gt; m_iconLabelTable =\n      new Hashtable&lt;Integer, JLabel&gt;();\n  \n  \/**\n   * Loads the images for the above icon labels\n   *\/\n  private void loadImages()\n  {\n    \/\/ Image file names are relative to the current class\n    final String&#x5B;] iconPaths =\n    {\n      &quot;images\/nine.gif&quot;, &quot;images\/ten.gif&quot;,\n      &quot;images\/jack.gif&quot;, &quot;images\/queen.gif&quot;,\n      &quot;images\/king.gif&quot;, &quot;images\/ace.gif&quot;\n    };\n    \n    \/\/ Initialize the icon label table\n    Class base = this.getClass();\n    int i = 0;\n    for (String path : iconPaths)\n    {\n      ImageIcon icon =\n          ImageUtilities.createImageIcon(base, path);\n      m_iconLabelTable.put(i, new JLabel(icon));\n      i += 20;\n    }\n  }\n\n  \/\/\/\/\/\/\/\/ Inner classes \/\/\/\/\/\/\/\/\n  \n  \/**\n   * This class handles the label type radio button actions\n   *\/\n  class LabelTypeActionHandler\n      implements ActionListener\n  {\n    public void actionPerformed(ActionEvent event)\n    {\n      String command =\n          m_labelsGroup.getSelection().getActionCommand();\n      if (command.equals(DEFAULT))\n      {\n        m_slider.setLabelTable(null);\n        m_slider.setPaintLabels(m_labels.isSelected());\n      }\n      else if (command.equals(CUSTOM))\n      {\n        m_slider.setLabelTable(m_labelTable);\n      }\n      else if (command.equals(ICONS))\n      {\n        m_slider.setLabelTable(m_iconLabelTable);\n      }\n      \n      \/\/ Repaint\/resize frame\n      repaintFrame();\n    }\n  }\n  \n  \/**\n   * This class handles the orientation radio\n   * button actions.\n   *\/\n  class OrientationHandler\n      implements ActionListener\n  {\n    public void actionPerformed(ActionEvent event)\n    {\n      String action = event.getActionCommand();\n      if (action.equals(HORIZONTAL))\n      {\n        m_slider.setOrientation(JSlider.HORIZONTAL);\n      }\n      else if (action.equals(VERTICAL))\n      {\n        m_slider.setOrientation(JSlider.VERTICAL);\n      }\n      repaintFrame();\n    }\n  }\n  \n  \/**\n   * Main entry point, for testing\n   *\/\n  public static void main(String&#x5B;] args)\n  {\n    JFrame frame = new JFrame();\n    JPanel panel = (JPanel)frame.getContentPane();\n    panel.setLayout( new BorderLayout() );\n    \n    JPanel sliderPanel = new JPanel();\n    JSlider slider = new JSlider();\n    slider.setBorder(\n        BorderFactory.createLineBorder(Color.BLUE));\n    slider.setMajorTickSpacing(20);\n    slider.setMinorTickSpacing(5);\n    sliderPanel.add(slider);\n\n    panel.add(sliderPanel, BorderLayout.CENTER);\n    panel.add( new ControlPanel(slider), BorderLayout.SOUTH );\n    frame.pack();\n    frame.setVisible(true);\n  }\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\nutton);\n      button.addActionListener(this);\n    }\n  }\n  \n  \/\/ Required for ActionListener\n  public void actionPerformed(ActionEvent event)\n  {\n    \/\/ Responds to the specified action by dynamically\n    \/\/ changing the look and feel of the application.\n    String action = event.getActionCommand();\n    Window ancestor = SwingUtilities.getWindowAncestor(this);\n    LookAndFeel.setLookAndFeel(action, ancestor);\n    ancestor.pack();\n  }\n  \n  \/\/\/\/\/ Private data \/\/\/\/\/\n  \n  \/\/ Radio buttons for showing look and feel rendering of slider\n  private ButtonGroup m_feelGroup = new ButtonGroup();\n  private String&#x5B;] m_feelCommands =\n  {\n    LookAndFeel.METAL, LookAndFeel.SYSTEM, LookAndFeel.MOTIF\n  };\n  private JRadioButton&#x5B;] m_feelButtons =\n  {\n    new JRadioButton(LookAndFeel.METAL, true),\n    new JRadioButton(LookAndFeel.SYSTEM),\n    new JRadioButton(LookAndFeel.MOTIF)\n  };\n  \/\/ Add radio buttons to button group\n  {\n    int index = 0;\n    for (JRadioButton button : m_feelButtons)\n    {\n      if (index == 0)\n        button.setSelected(true);\n      m_feelGroup.add(button);\n      String command = m_feelCommands&#x5B;index++];\n      button.setActionCommand(command);\n    }\n  }\n\n  \/**\n   * Main entry point, for testing\n   *\/\n  public static void main(String&#x5B;] args)\n  {\n    JFrame frame = new JFrame();\n    JPanel panel = (JPanel) frame.getContentPane();\n    panel.add( \n        new FeelPanel(SwingConstants.VERTICAL),\n        BorderLayout.WEST);\n    panel.add( \n        new FeelPanel(SwingConstants.HORIZONTAL),\n        BorderLayout.NORTH);\n    frame.pack();\n    frame.setVisible(true);\n  }\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingExamples;\n\nimport java.awt.Component;\nimport javax.swing.SwingUtilities;\nimport javax.swing.UIManager;\nimport javax.swing.UnsupportedLookAndFeelException;\n\n\/**\n * A class to provide support for changing look and feel.\n *\n * @author Bryan Higgs\n * @version 1.0\n *\/\npublic abstract class LookAndFeel\n{\n  public static final String METAL   = &quot;Metal&quot;,\n                             SYSTEM  = &quot;System&quot;,\n                             MOTIF   = &quot;Motif&quot;;\n  \n  \/**\n   * Changes look and feel and changes it dynamically for \n   * the component tree starting at component.\n   *\/\n  public static void setLookAndFeel(String feel, \n                                    Component component)\n  {\n    if (feel != null)\n    {\n      if (feel.equals(METAL))\n      {\n        feel = UIManager.getCrossPlatformLookAndFeelClassName();\n      }\n      else if (feel.equals(SYSTEM))\n      {\n        feel = UIManager.getSystemLookAndFeelClassName();\n      }\n      else if (feel.equals(MOTIF))\n      {\n        feel = &quot;com.sun.java.swing.plaf.motif.MotifLookAndFeel&quot;;\n      }\n      else\n      {\n        System.err.println(\n            &quot;Unexpected value of look and feel specified: &quot;\n            + feel);\n        feel = UIManager.getCrossPlatformLookAndFeelClassName();\n      }\n      \n      try\n      {\n        UIManager.setLookAndFeel(feel);\n        SwingUtilities.updateComponentTreeUI(component);\n      }\n      catch (ClassNotFoundException e)\n      {\n        System.err.println(\n            &quot;Couldn&#039;t find class for specified look and feel:&quot;\n            + feel);\n        System.err.println(\n            &quot;Did you include the L&amp;F library in the class path?&quot;);\n        System.err.println(&quot;Using the default look and feel.&quot;);\n      }\n      catch (UnsupportedLookAndFeelException e)\n      {\n        System.err.println(\n            &quot;Can&#039;t use the specified look and feel (&quot;\n            + feel + &quot;) on this platform.&quot;);\n        System.err.println(&quot;Using the default look and feel.&quot;);\n      }\n      catch (Exception e)\n      {\n        System.err.println(\n            &quot;Couldn&#039;t get specified look and feel (&quot;\n            + feel + &quot;), for some reason.&quot;);\n        System.err.println(&quot;Using the default look and feel.&quot;);\n        e.printStackTrace();\n      }\n    }\n  }\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingExamples;\n\nimport java.awt.Toolkit;\nimport java.io.BufferedInputStream;\nimport java.io.IOException;\nimport javax.swing.ImageIcon;\n\n\/**\n * A class to provide utility methods for dealing\n * with images and icons.\n *\n * @author Bryan Higgs\n * @version 1.0\n *\/\npublic abstract class ImageUtilities\n{\n  \/**\n   * Returns an ImageIcon, or null if the path was invalid\n   * When running  using Java Plug-in, getResourceAsStream\n   * is more efficient than getResource\n   *\/\n  protected static ImageIcon createImageIcon(\n                                Class baseClass, String path)\n  {\n    int MAX_IMAGE_SIZE = 124000;\n            \/\/ Change this to the size of\n            \/\/ the largest image, in bytes\n    int count = 0;\n    BufferedInputStream imgStream = new BufferedInputStream(\n        baseClass.getResourceAsStream(path));\n    if (imgStream != null)\n    {\n      byte buf&#x5B;] = new byte&#x5B;MAX_IMAGE_SIZE];\n      try\n      {\n        count = imgStream.read(buf);\n      }\n      catch (IOException ieo)\n      {\n        System.err.println(\n            &quot;Couldn&#039;t read stream from file: &quot; + path);\n      }\n      \n      try\n      {\n        imgStream.close();\n      }\n      catch (IOException ieo)\n      {\n        System.err.println(&quot;Can&#039;t close file &quot; + path);\n      }\n      \n      if (count &lt;= 0)\n      {\n        System.err.println(&quot;Empty file: &quot; + path);\n        return null;\n      }\n      return new ImageIcon(\n          Toolkit.getDefaultToolkit().createImage(buf));\n    }\n    else\n    {\n      System.err.println(&quot;Couldn&#039;t find file: &quot; + path);\n      return null;\n    }\n  }\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">which produces something that, on my Microsoft Windows system, looks like this:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img fetchpriority=\"high\" decoding=\"async\" width=\"401\" height=\"368\" src=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider16.jpg\" alt=\"\" class=\"wp-image-1085\" srcset=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider16.jpg 401w, https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider16-300x275.jpg 300w\" sizes=\"(max-width: 401px) 100vw, 401px\" \/><\/figure><\/div>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">and if you click on the Look and Feel radio buttons, you&#8217;ll see changes like:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img decoding=\"async\" width=\"377\" height=\"376\" src=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider17.jpg\" alt=\"\" class=\"wp-image-1086\" srcset=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider17.jpg 377w, https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider17-300x300.jpg 300w, https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider17-150x150.jpg 150w\" sizes=\"(max-width: 377px) 100vw, 377px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img decoding=\"async\" width=\"402\" height=\"400\" src=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider18.jpg\" alt=\"\" class=\"wp-image-1087\" srcset=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider18.jpg 402w, https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider18-300x300.jpg 300w, https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Slider18-150x150.jpg 150w\" sizes=\"(max-width: 402px) 100vw, 402px\" \/><\/figure><\/div>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">As you set or unset the appropriate checkboxes and radio buttons, the slider changes its visual appearance.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><strong><em>Note:<\/em><\/strong>&nbsp;Be patient when changing Look and Feel in this application.&nbsp; On occasion, I have found the System look and feel to be rather sluggish the first time it&#8217;s selected.<\/p><\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Spinners\"><\/span>Spinners<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A&nbsp;<strong><em>spinner<\/em><\/strong>&nbsp;is a component somewhat similar to a combo box, but it shows only one item.&nbsp; It is represented by the&nbsp;<code><strong>JSpinner<\/strong><\/code>&nbsp;class, and provides up and down arrows to move through its set of values.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Spinners were introduced in Java 1.4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A spinner is relatively flexible;&nbsp; you can set a spinner up to work with a number of different choices, including bounded ranges such as days of the week, months of the year, etc., and also unbounded ranges such as the set of integers, etc.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As with other Swing components, you change the set of values a spinner is associated with by setting up an appropriate spinner model.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s an example:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; highlight: [15,16,17,18,20,21,36,38,45,48,50,51,62,63,64,65,66,67,68,69,70,71,72]; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingExamples;\n\nimport java.awt.BorderLayout;\nimport java.awt.Container;\nimport java.awt.GridLayout;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\n\nimport javax.swing.BorderFactory;\nimport javax.swing.ButtonGroup;\nimport javax.swing.JFrame;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.JRadioButton;\nimport javax.swing.JSpinner;\nimport javax.swing.SpinnerDateModel;\nimport javax.swing.SpinnerListModel;\nimport javax.swing.SpinnerModel;\nimport javax.swing.SpinnerNumberModel;\nimport javax.swing.SwingUtilities;\nimport javax.swing.event.ChangeEvent;\nimport javax.swing.event.ChangeListener;\n\nclass SpinnersPanel extends JPanel\n{\n  public SpinnersPanel()\n  {\n    setLayout( new GridLayout(0, 3, 10, 10) );\n    setBorder(\n        BorderFactory.createCompoundBorder(\n        BorderFactory.createEmptyBorder(5, 5, 5, 5),\n        BorderFactory.createTitledBorder(&quot;Spinners:&quot;)\n        ) );\n    \n    addSpinner( &quot;Basic Spinner&quot;,\n        new JSpinner() );\n    addSpinner( &quot;Date Spinner&quot;,\n        new JSpinner( new SpinnerDateModel() ) );\n    String&#x5B;] weekdays =\n    {\n      &quot;Sunday&quot;, &quot;Monday&quot;, &quot;Tuesday&quot;, &quot;Wednesday&quot;,\n      &quot;Thursday&quot;, &quot;Friday&quot;, &quot;Saturday&quot;\n    };\n    addSpinner( &quot;List Spinner&quot;,\n        new JSpinner( new SpinnerListModel(weekdays) ) );\n    addSpinner( &quot;Number Spinner&quot;,\n        new JSpinner(\n             new SpinnerNumberModel(0, 0, 100, 5) ) );\n    addSpinner( &quot;Rollover List Spinner (custom)&quot;,\n        new JSpinner(\n             new RolloverSpinnerListModel(weekdays) ) );\n  }\n  \n  private void addSpinner(String description,\n      JSpinner spinner)\n  {\n    add( new JLabel(description) );\n    add(spinner);\n    final JLabel valueLabel = \n        new JLabel( spinner.getValue().toString() );\n    add(valueLabel);\n    spinner.addChangeListener( \n        new ChangeListener()\n        {\n          public void stateChanged(ChangeEvent event)\n          {\n            JSpinner source = (JSpinner)event.getSource();\n            SpinnerModel model = source.getModel();\n            valueLabel.setText( model.getValue().toString() );\n          }\n        }\n    );\n  }\n \n  \/**\n   * Finds the application&#039;s JFrame and &#x5B;re]packs it.\n   *\/\n  private void repaintFrame()\n  {\n    SwingUtilities.getWindowAncestor(this).pack();\n  }\n\n  \/\/ Radio buttons for showing look and feel rendering of slider\n  private ButtonGroup m_feelGroup = new ButtonGroup();\n  private String&#x5B;] m_feelCommands =\n  {\n    LookAndFeel.METAL, LookAndFeel.SYSTEM, LookAndFeel.MOTIF\n  };\n  private JRadioButton&#x5B;] m_feelButtons =\n  {\n    new JRadioButton(LookAndFeel.METAL, true),\n    new JRadioButton(LookAndFeel.SYSTEM),\n    new JRadioButton(LookAndFeel.MOTIF)\n  };\n  \/\/ Add radio buttons to button group\n  {\n    int index = 0;\n    for (JRadioButton button : m_feelButtons)\n    {\n      if (index == 0)\n        button.setSelected(true);\n      m_feelGroup.add(button);\n      String command = m_feelCommands&#x5B;index++];\n      button.setActionCommand(command);\n    }\n  }\n}\n\npublic class Spinners extends JFrame\n{\n  public Spinners()\n  {\n    super(&quot;Spinners&quot;);\n    setDefaultCloseOperation(EXIT_ON_CLOSE);\n    Container container = getContentPane();\n    container.setLayout( new BorderLayout() );\n    container.add( \n        new SpinnersPanel(), BorderLayout.CENTER );\n    container.add(\n        new FeelPanel(), BorderLayout.SOUTH );\n    setVisible(true);\n    pack();\n  }\n  \n  \/**\n   * Main entry point for application\n   *\/\n  public static void main(String&#x5B;] args)\n  {\n    JFrame frame = new Spinners();\n    frame.setVisible(true);\n  }\n}\n\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; highlight: [4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44]; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingExamples;\n\nimport java.util.List;\nimport javax.swing.SpinnerListModel;\n\n\/**\n * A class to implement a &quot;rollover&quot; list model\n * for a JSpinner.  That is, it behaves like a\n * normal spinner list model, except that when\n * you move beyond the last item, or before the\n * first item, it &quot;wraps around&quot;.\n *\/\npublic class RolloverSpinnerListModel\n    extends SpinnerListModel\n{\n  public RolloverSpinnerListModel(Object&#x5B;] items)\n  {\n    super(items);\n  }\n  \n  public RolloverSpinnerListModel(List items)\n  {\n    super(items);\n  }\n  \n  public Object getNextValue()\n  {\n    Object nextValue = super.getNextValue();\n    if (nextValue == null)\n      nextValue = getList().get(0);\n    return nextValue;\n  }\n  \n  public Object getPreviousValue()\n  {\n    Object prevValue = super.getPreviousValue();\n    if (prevValue == null)\n    {\n      List list = getList();\n      prevValue = list.get(list.size() - 1);\n    }\n    return prevValue;\n  }\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">(The&nbsp;<code><strong>FeelPanel<\/strong><\/code>&nbsp;and&nbsp;<code><strong>LookAndFeel<\/strong><\/code>&nbsp;classes are the same as in the <strong>Sliders<\/strong> example.)<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"561\" height=\"270\" src=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Spinne13.jpg\" alt=\"\" class=\"wp-image-1103\" srcset=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Spinne13.jpg 561w, https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Spinne13-300x144.jpg 300w\" sizes=\"(max-width: 561px) 100vw, 561px\" \/><figcaption>Here&#8217;s what it looks like initially.<\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"480\" height=\"277\" src=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Spinne14.jpg\" alt=\"\" class=\"wp-image-1104\" srcset=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Spinne14.jpg 480w, https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Spinne14-300x173.jpg 300w\" sizes=\"(max-width: 480px) 100vw, 480px\" \/><figcaption>When I switch it to the System (in my case Microsoft Windows) L&amp;F it looks like this.<\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"548\" height=\"278\" src=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Spinne15.jpg\" alt=\"\" class=\"wp-image-1105\" srcset=\"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Spinne15.jpg 548w, https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-content\/uploads\/2021\/01\/Spinne15-300x152.jpg 300w\" sizes=\"(max-width: 548px) 100vw, 548px\" \/><figcaption>And when I switch it to the Motif L&amp;F.<\/figcaption><\/figure><\/div>\n\n\n\n<div style=\"height:37px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Java Swing has introduced some new Swing components: Sliders, and Spinners Here are some details&#8230; Sliders A&nbsp;slider&nbsp;control allows a user to choose from a continuum of values between a minimum and maximum value.&nbsp; Sliders were introduced in Java 1.4, and behave somewhat like scrollbars, except that they can be visually configured in a more pleasing [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":71,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_eb_attr":"","_uag_custom_page_level_css":"","ocean_front_end_style_editor":"no","ocean_post_layout":"left-sidebar","ocean_both_sidebars_style":"","ocean_both_sidebars_content_width":0,"ocean_both_sidebars_sidebars_width":0,"ocean_sidebar":"ocs-course-topics-sidebar","ocean_second_sidebar":"0","ocean_disable_margins":"enable","ocean_add_body_class":"","ocean_shortcode_before_top_bar":"","ocean_shortcode_after_top_bar":"","ocean_shortcode_before_header":"","ocean_shortcode_after_header":"","ocean_has_shortcode":"","ocean_shortcode_after_title":"","ocean_shortcode_before_footer_widgets":"","ocean_shortcode_after_footer_widgets":"","ocean_shortcode_before_footer_bottom":"","ocean_shortcode_after_footer_bottom":"","ocean_display_top_bar":"default","ocean_display_header":"default","ocean_header_style":"","ocean_center_header_left_menu":"0","ocean_custom_header_template":"0","ocean_custom_logo":0,"ocean_custom_retina_logo":0,"ocean_custom_logo_max_width":0,"ocean_custom_logo_tablet_max_width":0,"ocean_custom_logo_mobile_max_width":0,"ocean_custom_logo_max_height":0,"ocean_custom_logo_tablet_max_height":0,"ocean_custom_logo_mobile_max_height":0,"ocean_header_custom_menu":"0","ocean_menu_typo_font_family":"0","ocean_menu_typo_font_subset":"","ocean_menu_typo_font_size":0,"ocean_menu_typo_font_size_tablet":0,"ocean_menu_typo_font_size_mobile":0,"ocean_menu_typo_font_size_unit":"px","ocean_menu_typo_font_weight":"","ocean_menu_typo_font_weight_tablet":"","ocean_menu_typo_font_weight_mobile":"","ocean_menu_typo_transform":"","ocean_menu_typo_transform_tablet":"","ocean_menu_typo_transform_mobile":"","ocean_menu_typo_line_height":0,"ocean_menu_typo_line_height_tablet":0,"ocean_menu_typo_line_height_mobile":0,"ocean_menu_typo_line_height_unit":"","ocean_menu_typo_spacing":0,"ocean_menu_typo_spacing_tablet":0,"ocean_menu_typo_spacing_mobile":0,"ocean_menu_typo_spacing_unit":"","ocean_menu_link_color":"","ocean_menu_link_color_hover":"","ocean_menu_link_color_active":"","ocean_menu_link_background":"","ocean_menu_link_hover_background":"","ocean_menu_link_active_background":"","ocean_menu_social_links_bg":"","ocean_menu_social_hover_links_bg":"","ocean_menu_social_links_color":"","ocean_menu_social_hover_links_color":"","ocean_disable_title":"default","ocean_disable_heading":"default","ocean_post_title":"","ocean_post_subheading":"","ocean_post_title_style":"","ocean_post_title_background_color":"","ocean_post_title_background":0,"ocean_post_title_bg_image_position":"","ocean_post_title_bg_image_attachment":"","ocean_post_title_bg_image_repeat":"","ocean_post_title_bg_image_size":"","ocean_post_title_height":0,"ocean_post_title_bg_overlay":0.5,"ocean_post_title_bg_overlay_color":"","ocean_disable_breadcrumbs":"default","ocean_breadcrumbs_color":"","ocean_breadcrumbs_separator_color":"","ocean_breadcrumbs_links_color":"","ocean_breadcrumbs_links_hover_color":"","ocean_display_footer_widgets":"default","ocean_display_footer_bottom":"default","ocean_custom_footer_template":"0","footnotes":""},"class_list":["post-1081","page","type-page","status-publish","hentry","entry"],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false,"ocean-thumb-m":false,"ocean-thumb-ml":false,"ocean-thumb-l":false},"uagb_author_info":{"display_name":"Bryan Higgs","author_link":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/author\/bryan\/"},"uagb_comment_info":0,"uagb_excerpt":"Java Swing has introduced some new Swing components: Sliders, and Spinners Here are some details&#8230; Sliders A&nbsp;slider&nbsp;control allows a user to choose from a continuum of values between a minimum and maximum value.&nbsp; Sliders were introduced in Java 1.4, and behave somewhat like scrollbars, except that they can be visually configured in a more pleasing&hellip;","_links":{"self":[{"href":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-json\/wp\/v2\/pages\/1081","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-json\/wp\/v2\/comments?post=1081"}],"version-history":[{"count":21,"href":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-json\/wp\/v2\/pages\/1081\/revisions"}],"predecessor-version":[{"id":1111,"href":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-json\/wp\/v2\/pages\/1081\/revisions\/1111"}],"up":[{"embeddable":true,"href":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-json\/wp\/v2\/pages\/71"}],"wp:attachment":[{"href":"https:\/\/bhiggs.x10hosting.com\/PracticalJavaProgramming\/wp-json\/wp\/v2\/media?parent=1081"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}