1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Development Java ~ Create Graphical Dials

Discussion in 'Software' started by Strudul, 22 Dec 2016.

  1. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    I want to create some stuff in Java, but have no idea where to start.

    The first task I'm attacking is to create some dials like these:
    [​IMG]
    (The white bar will be animated and reflect the value of the numbers)

    Any help would be appreciated, I'm still relatively new to Java and my GUI programming abilities are pretty minimal.

    I tried Googling, but couldn't find anything useful.

    Cheers
     
    Last edited: 22 Dec 2016
  2. theshadow2001

    theshadow2001 [DELETE] means [DELETE]

    Joined:
    3 May 2012
    Posts:
    5,284
    Likes Received:
    183
    Java is a little awkward for this kind of stuff. I'll try and knock a few things together to get you started tomorrow...maybe.
     
  3. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    Cheers, anything at all should help. :)
     
  4. theshadow2001

    theshadow2001 [DELETE] means [DELETE]

    Joined:
    3 May 2012
    Posts:
    5,284
    Likes Received:
    183
    This program reads values in from the console and then draws the images according to the input. See how you get on with it. Post any questions that you have and I'll try to answer.
    Code:
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.event.WindowAdapter;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import java.util.Scanner;
    
    public class Dial {
    
    	public static void main(String[] args) {
    		//A JFrame is the main window
    		final JFrame frame = new JFrame();
    		
    		//prevent automatic close operation as it needs to be done progamatically
    		frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    		frame.setVisible(true);	//we need to see the window
    		frame.setSize(270, 200);
    		frame.setBackground(Color.BLACK); 
    		
    		//A JPanel is what we draw on (see class below)
    		DrawPanel panel = new DrawPanel();
    
    		//add the panel to the frame
    		frame.setContentPane(panel);
    
    		//input scanner reads the input value from the console.
    		//the scanner is final to allow access in the window listener
    		final Scanner scanner = new Scanner(System.in);
    
    		//variables to handle user input
    		String angleInput;
    		int angle = 0;
    
    		//pick up the window close event to close the input scanner and dispose of
    		//the window
    		frame.addWindowListener(new WindowAdapter(){
    			@Override
    			public void windowClosing(java.awt.event.WindowEvent windowEvent){
    				frame.dispose();
    				scanner.close();
    				System.exit(0);
    			}
    		});
    
    		//loop reads input from console and sets the arc
    		while(true){
    			//read console input as string
    			angleInput = scanner.nextLine();
    			try{
    				//parse string to int
    				angle = Integer.parseInt(angleInput);
    			}catch (Exception e){
    				//catches errors and restarts the loop if non-int is entered
    				System.out.println("Gotta catch'em all");
    				continue;
    			}
    			//set the angle of the dangle and call the repaint method
    			//to redraw the panel with the new arc values
    			panel.setAngle(angle);
    			panel.repaint();
    		}
    		
    		
    	}
    }
    //Need to override the paint method of JPanel to draw things
    //so a class that inherits from a JPanel is required
    class DrawPanel extends JPanel{
    
    	//something to get rid of a warning. Not required
    	private static final long serialVersionUID = 1L;
    
    	private int angle = 0;
    	private int displayValue = 0;
    
    	public void setAngle(int angle){
    		if (angle < 0)
    			angle = 0;
    		if (angle > 180)
    			angle = 180;
    
    		this.angle = 180 - angle;
    		this.displayValue = angle;
    	}
    	
    	public int getAngle(){
    		return this.angle;
    	}
    
    	//Override indicator, paint method must be overridden in order
    	//to draw shapes
    	@Override
    	public void paintComponent(Graphics g){
    		//three fill arcs are used to create the dial
    		//change colours to see what's going on
    		g.setColor(Color.WHITE);
            g.fillArc(50, 50, 150, 150, 0, 180);
    		g.setColor(Color.BLACK);
            g.fillArc(60, 60, 130, 130, 0, 180);
    		g.setColor(Color.BLACK);
            g.fillArc(40, 40, 170, 170, 0, angle);
            g.setColor(Color.WHITE);
            
            //Text Strings
            g.drawString("Min 0",50, 140); 
            g.drawString("Max 180",150, 140); 
            g.drawString(String.valueOf(displayValue), 120, 100);
            g.drawString("Speed MPH", 90, 115);
    
    	}
    }
    [​IMG]
     
    Strudul likes this.
  5. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    That looks great. I'll have a play after dinner. :thumb:

    Cheers.
     
  6. theshadow2001

    theshadow2001 [DELETE] means [DELETE]

    Joined:
    3 May 2012
    Posts:
    5,284
    Likes Received:
    183
    There's a bug in how it exits. But it's close enough for sample code.
     
  7. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    Had a tinker and it's working nicely. The comments were really helpful.

    Now, since I want multiple dials on screen at once, what's the best way to go about this?

    I could just stick the other dials in that class, drawing the other arcs (dials) in different places on the frame using different names, but I assume I will be severely reprimanded for even thinking about doing it that way.

    So instead, I guess I need a class that sets up the frame and then calls that dial class (with a bit of modification) passing values to define the variables (arc locations, text names, input variable)?
     
  8. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    Got 2 running at the moment, but using the taboo method :nono:

    [​IMG]
     
  9. theshadow2001

    theshadow2001 [DELETE] means [DELETE]

    Joined:
    3 May 2012
    Posts:
    5,284
    Likes Received:
    183
    Good stuff. I would create a configurable dial class. Then an array list or similar data structure to hold each class instance. Then pass that data structure into the draw panel class.

    The procedure would be instanciate a dial class setting up the text and max and min in the constructor. Add the instance to a collection. Set the value for each dial. Pass the collection to the draw panel class then draw each dial.

    I would also add a layout method to the draw panel class which automatically lays out the dials depending on the size of the window and how many dials you have. That might warrant it's own layout manager class depending on how complex it is.
     
  10. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    Is there any way to easily align the drawStrings?

    Currently when another digit is added it shifts the whole thing to the right e.g.

    Code:
    99
    100
    999
    1000
    Instead, I want it to just add that digit onto the left, with the units staying stationary e.g.
    Code:
      99
     100
     999
    1000
     
    Last edited: 25 Dec 2016
  11. theshadow2001

    theshadow2001 [DELETE] means [DELETE]

    Joined:
    3 May 2012
    Posts:
    5,284
    Likes Received:
    183
    There doesn't appear to be a way because the drawString uses the XY co-ordinate of the left side to determine its position. If you are using multiple strings you could probably align by estimating the pixel length of the string based on the number of characters and then calculate the necessary X co-ordinate offset to do right side alignment.

    The above method might not work too well if the font isn't very monospacey so you could use the drawChars method or 1 character strings and position each character individually which is probably more work, but you might get a better looking result.

    You could also change the font to something that is monospaced if that helps. But I don't know how to do it off hand.

    Left padding with spaces would be another option.
     
  12. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    It's for when the speed for example goes from 99 to 100, the units and tens digits stay where they are and the hundreds will just be appended onto the left instead of pushing everything right.

    Your suggestions are the same conclusions I came to, sounded too messy to be the only way to do it though.
     
  13. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    Just padded everything with extra zeros based on the value. Not sure how I feel about having them visible, quite like it, but might hide them.

    Also got AA on the dials now :thumb:
    [​IMG]
     
  14. theshadow2001

    theshadow2001 [DELETE] means [DELETE]

    Joined:
    3 May 2012
    Posts:
    5,284
    Likes Received:
    183
    Yes it is messy, but if you encapsulate the code in a class or a method, you can hide the mess away somewhere :D . Setting a max character limit and left padding with spaces would be a small enough piece of work.

    You could start looking at using JLabels or similar plus a layout manager, but the complexity would go up a fair bit. Layout managers are a pain in the arse to use. But it would give you better control over how text is arranged. Layout mangers are used to create more standard, form-style desktop GUI applications.

    If you go down that route you would probably be looking at setting up your text with a layout manager and then trying to layer the JPanel on top of it all (or vice versa more likely).

    Edit: I think it looks alright with the zeros. Spaces would be fine too. Yes it looks a lot better with anti-aliasing.
     
  15. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    Yeah, most of my Java experience was using layout mangers (GridBag mainly), but for the application it should be at a fixed resolution and window size. It may be bad practice to use definite values for locations and sizes (for obvious reasons), but it gives me more control and stops everything moving around whenever i make changes.
     
  16. theshadow2001

    theshadow2001 [DELETE] means [DELETE]

    Joined:
    3 May 2012
    Posts:
    5,284
    Likes Received:
    183
    Nah, if you can guarantee resolution and size for your application, there's no point in adding the flexibility a layout manager would provide as it would just be more work for redundant functionality.
     
  17. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    I can guarantee it being fixed for it's intended application, but the extra flexibility is always nice if I every want to reuse the code for a different purpose or develop it further.

    Not gonna go making extra work for myself though, at least for now.
     
  18. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    Any way to make a key listener that doesn't require focus? Eventually I may need to have some level of control with an external switch / button, but for now a key press will do. Everything seems to require a text box with focus though - I just want it to respond if it's the active window (e.g. press 2 to display panel 2 etc).

    Been busy working on other functionality too (suggestions / criticism appreciated):
    [​IMG]

    [​IMG]

    [​IMG]
     
  19. theshadow2001

    theshadow2001 [DELETE] means [DELETE]

    Joined:
    3 May 2012
    Posts:
    5,284
    Likes Received:
    183
  20. Strudul

    Strudul ~

    Joined:
    31 May 2010
    Posts:
    947
    Likes Received:
    35
    Yeah, looked into those, but couldn't get it to work. Will have another bash later.
     

Share This Page