Domanda

For a University assignment I’m making a java implementation of Solving the Travelling Salesman Problem. I will be cutting out most of the code to make it less “busy” however if it no longer makes sense, please let me know. To make it work I have a class which draws the window with all the UI;

//suitable imports
public class Window extends JFrame implements ActionListener
{
    int gridX = 0;
    int gridY = 0;
    String[] xyLength = 
    {
        "1", "2", "3", "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", "45", "46", "47", "48", "49", "50"
    };
    Canvas canvas = new Canvas();
    JPanel mainPanel = new JPanel(); 

    JPanel westPanel = new JPanel(); //Panel on the left which houses controls
    JComboBox<String> xSelectComboBox = new JComboBox<String>(xyLength);
    JComboBox<String> ySelectComboBox = new JComboBox<String>(xyLength);
    JButton redrawButton = new JButton(“Redraw”);
    JButton generateButton = new JButton(“Generate”);

    public static void main(String[] args)
    {
        new Window();
    }

    public Window()
    {
        super(“Travelling Salesman Problem”);
        setSize(900, 620);
        setResizeable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        mainPanel.setLayout(new BorderLayout());

        mainPanel.add(canvas, BorderLayout.CENTER);

        westPanel.add(xSelectComboBox);
        westPanel.add(ySelectComboBox);
        redrawButton.addActionListener(this);
        westPanel.add(redrawButton);
        generateButton.addActionListener(this);
        westPanel.add(generateButton);
        mainPanel.add(westPanel, BorderLayout.WEST);

        add(mainPanel);
        setVisible(true);
    }

    public void actionPerformed(ActionEvent e)
    {
        Object source = e.getSource();
        if(source.equals(redrawButton)
        {
            gridX = Integer.parseInt((xSelectComboBox.getSelectedItem()).toString());
            gridY = Integer.parseInt((ySelectComboBox.getSelectedItem()).toString());
            canvas.setXLength(gridX);
            canvas.setYLength(gridY);
            canvas.repaint();
        }
        if(source.equals(generateButton))
        {
            Algorithms.randomRoute(gridX, gridY);
        }  
    }
}

I also have the Canvas class which contains the paint component;

//suitable imports
public class Canvas extends JPanel
{
    int process = 0;
    int xLength;
    int yLength;
    Node point = new Node();

    public Canvas()
    {
        xLength = 0;
        yLength = 0;
    }

    public void setProcess(int set)
    {
        process = set;
    }

    public void setXLength(int x)
    {
        xLength = x;
    }

    public void setYLength(int y)
    {
        yLength = y;
    }

    public setNode(Node n)
    {
        point.copy(n)
    }

    public void paintComponent(Graphics g)
    {
        super paintComponent(g);
        switch(process)
        {
            case 0:
                drawGrid(g);
                break;
            case 1:
                point.draw(g);
                break;
        }
    }

    public void drawGrid(Graphics g)
    {
        //draws a grid based upon xLength and yLength
    }
}

Thirdly I have a Node Object within which I want there to be a draw(g) method;

//suitable imports
public class Node
{
    protected int xCoordinate;
    protected int yCoordinate;
    protected boolean visitedFlag;

    //skipping constructors, sets and gets
    public void draw(Graphics g)
    {
        g.setColor(Color.red);
        g.fillArc(xCoordinate, yCoordinate, 6, 6, 0 ,360);
    }
}

Finally I have an Algorithm class which will contain all the different algorithms for solving the problem, including a random route generator;

//suitable imports
public class Algorithms
{
    public void randomRoute(int xMax, int yMax)
    {
        nodeMax = 10;
        Node[] point = new Node[nodeMax];
        Random rand = new Random();
        for(int i = 0; i < nodeMax; i++)
        {
            point[i] = new Node();
            point[i].setXCoordinate(rand.nextInt(xMax);
            point[i].setYCoordinate(rand.nextInt(yMax);
            //insert drawing point[i] here
        }        
    }
}

The issue is, I’d like to keep my processing code separate from the Window class, but be able to draw on the instance of Canvas that I declare within Window. I also need to be able to refresh what is contained within paintComponent.

Any small issues within the code are as a result of me retyping it for the question

Thanks.

EDIT: So I've modified the Canvas (now MyCanvas) class method setProcess;

public void setProcess(int set)
{
    process = set;
    repaint();
}

I also can take in an array of Nodes;

public void setNode(Node[] n, int nodesMax)
{
    point = new Node[nodesMax];
    nodeMax = nodesMax;
    for(int i = 0; i < nodeMax - 1; i++)
    {
        point[i] = new Node();
        point[i].copy(n[i]);
    }
}

Finally, I also changed the switch case statement within paintComponent;

switch(process)
{
    case 1:
        drawGrid(g, this.xLength + 1, this.yLength + 1);
        process = 0;
        break;
    case 2:
        g.setColor(Color.red);
        for(int i = 0; i < nodeMax; i++)
        {
            g.fillArc((this.point[i].xCoordinate + 30), (this.point[i].yCoordinate + 30), 100, 100, 0, 360);
        }
        process = 0;
        break;
}

However, the repaint() within setProcess doesn't re-run paintComponent. Any ideas where I'm going wrong?

È stato utile?

Soluzione

Don't call your class Canvas. There is an AWT class of that name already so using the same name can cause confusion.

but be able to draw on the instance of Canvas that I declare within Window.

Don't don't do the drawing externally in another class.

Instead, if you want to make changes to the MyCanvas class, then you need to have a reference to the class and you need to create methods that will allow you to add/remove nodes as required. Then the addNode/removeNode methods would simply invoke repaint() and the MyCanvas class will repaint itself.

Edit:

process = set;
repaint();
process = 0;

You can't use logic like that. You can't control when the painting of a component is done. The repaint() method invokes the RepaintManager which will do the painting at an appropriate time. So by the time the paintComponent() method is invoked, the process variable will be 0. Just add a System.out.println(...) statement to your code to verify this.

The purpose of a set??? method is to change a property of a class. So just leave the value alone and don't reset it to 0.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top