I hate to write code like that

  • I just finished writing a WTF. Yes, this situation can be called real-time-WTF-injection or something like that. I am trying to get a better solution and to avoid my WTF. So code first, then the dilemma afterwards:


    private double ConvertPercentage(Object spinnerValue){
           String inputPercentage = (String)spinnerValue;
           double actualPercentage = -1;
               actualPercentage = 0;
           else if(inputPercentage.startsWith("25")){
               actualPercentage = 0.25;
           else if(inputPercentage.startsWith("50")){
               actualPercentage = 0.5;
           else if(inputPercentage.startsWith("75")){
               actualPercentage = 0.75;
           else if(inputPercentage.startsWith("100"))
               actualPercentage = 1;
           return actualPercentage;



    It feels so wrong. 


    The JSpinner Swing component (like a combination of textfield and combobox)  allows custom values. They can be numbers, a Date object and such. And it can be a List of given values that are e.g. Strings. If you have a range of String values such as (0%, 25 %, etc) and you want to respond correctly to the selection by the user then comparing these values in a hard-coded way seems an easy option. But it is of course a bad one... just imagine... what if tomorrow the selection should be between 0.33, 0.66.... you have to edit the UI component and the code that retrieves the input values and validates them before starting the background task....


    therefore my question:


    Please, if you can think of a better way of doing this, please write it here. 


  • I don't know anything about JSpinner, and I really don't know what language this is in, but why not convert the string to an integer, use your first if statement, and in the else, divide by 100?  Or did I just miss something in the translation here?


    May also want to make sure the integer is positive before dividing by 100 (unless negative percentages are ok). 

  • Umm... I'm not fluent in Java anymore, but how about this:


    private double ConvertPercentage(Object spinnerValue){
           String inputPercentage = (String)spinnerValue;
           inputPercentage = inputPercentage.substring(0, inputPercentage.length-2); //drop the %
           return Integer.ParseInt(inputPercentage.) / 100;

  • I probably think too simple here, but if I understand the documentation correctly, why aren't you just using numbers for you selection model instead of strings? It's not like there will be an option "Dennis" added to the spinner soon...

  • Upon further reading:

    [code]mySpinner.setModel(new SpinnerNumberModel(0,0,100,25));[/code]

    [code]private double ConvertPercentage(Object spinnerValue){[/code]
      [code]return spinnerValue.intValue/(double)100;[/code]


  • Using the NumberSpinnerModel is the correct solution IF you want to show numbers only.


    A not tested example :}


    JSpinner mySpinner; // Your JSpinner 

    SpinnerNumberModel myModel=new SpinnerNumberModel(0.5,0,1,0.1); // The args are default,min,max,stepsize



     To get the value as a number, you can either do

    double value=((SpinnerNumberModel)mySpinner.getModel()).getNumber().doubleValue();

    // Or simple keep a reference to your model and call

    double value=myModel.getNumber.doubleValue()


  • If you REALLY need a % sign behind the number, I'd say the easiest and most trouble-free way is to just put it on a label next to the whole control. Otherwise you wind up with the whole input format problem if the user wants to change the value manually: What if he forgets to type the sign, what if he puts a space between the sign and number, what if he types something entirely different and so on... Far more trouble than it's worth IMO.

  • To allow the entry of aribtary percentages, use the facilities provided by JSpinner.NumberEditor, which allows you to set formatting so that the numbers will appear as percentages, like this (also untested code):

    JSpinner spinner = new JPsinner();

    spinner.setEditor(new JSpinner.NumberEditor(spinner, "##%"));

    Or even, going slightly OTT,

    JSpinner spinner = new JSpinner();
    spinner.setEditor(new JSpinner.NumberEditor(spinner, DecimalFormat.getPercentInstance().toPattern()));

    which will allow any arbitary percentage, including non-integer values (42.7%, say) use the current locale's decimal format.

    If you want to only allow specific values (e.g. 0%, 25%, 50%, 75%, 100%) then if you want to have the percent sign in the textbox you could user a SpinnerListModel created from an array of the allowed vaules as strings, and then use luketheduke's "drop the % sign & divide by 100" code.

  • wow, thanks for the fast response !


    The main problem is that I created this GUI with Netbeans Matisse. I am afraid of editing some code that will be re-generated again and again. 


    The idea to entirely drop the "%"-sign and place it in a Label nearby is good. Then I can stay with numbers (0, 0.25, etc) and can forget about the conversion logic. And if I really have to change the values, it wont affect the logic that reads those input values.



    Thank you! 


    Edit: Thanks to the author of the post above, I did not event think about using Editors. Another sign that Swing is indeed flexible. 




  • Well, if you really want to get fancy you could define a class:

      class ListItem {

         private String str;

         private double val;

         public ListItem(String str, double val) {

             this.str = str; this.val = val; }

        public toString() { return str; }

        public value() { return val; }


    Then make a List containing ListItem("0%", 0.0); ListItem("25%", 0.25); etc.

    You could even have it fill the list by reading a configuration file or some XML.

    Remember, whatever the type is, Swing will call toString() to find out what to show for the item, and you can call value() or any other method on the selected item.


Log in to reply

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.