0

I have a project that uses JFreeChart.

The chart that I am using is displaying correctly and works fine with the current code. My problem is that I can only position the graph to the east, south, west, center or north of my JPanel.

My desire is to move this chart to any position inside my JPanel.

This is the short code snippet where I add my graph to the panSimulator JPanel. The problematic code is at the bottom of the ConfigurationFrame class:

public class ConfigurationFrame extends JFrame {

    private KettlerBikeConnector bike1 = null;

    private static final long serialVersionUID = 1L;
    
    CrosshairDemo chd = new CrosshairDemo();
    
    private JPanel panSimulator;
    private PanelBikeSimulator panBSim;

    private Timer timerBike;
    private TimerListener listener;

    private final int UPDATE_MS = 1000; // updates every second

    private JTabbedPane tabPane;
    private JPanel panConfiguration;
    private JPanel panGame;
    private JComboBox<String> cbxPort;
    private JTextPane lblStatus;

    // to have access to the textfield
    public static JTextField txtEnergy;
    public static JTextField txtDistance;
    public static JTextField txtHeartRate;
    public static JTextField txtTime;

    public File path = null;

    public int key = -1;

    boolean run = true;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ConfigurationFrame frame = new ConfigurationFrame();
                    frame.setVisible(true);
                    // frame.pack(); // give a suitable size to window automatically
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     * @throws IOException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
     */
    public ConfigurationFrame() throws ParserConfigurationException, SAXException, IOException {        

        setResizable(false);
        setMinimumSize(new Dimension(1900, 1000));
        setTitle("Bike Simulation ... I need a name ...");
        setLocationRelativeTo(null);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent arg0) {
                try {
                    timerBike.stop();
                    bike1.close();
                } catch (Exception e) {
                    log(e.getMessage());
                }
            }
        });
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        getContentPane().setLayout(null);



        // Panel
        tabPane = new JTabbedPane(JTabbedPane.TOP);
        tabPane.setFont(new Font("Tahoma", Font.PLAIN, 24));
        tabPane.setBounds(0, 0, 1892, 994);
        getContentPane().add(tabPane);

        // Configuration-Panel
        panConfiguration = new JPanel();
        tabPane.addTab("Configuration", null, panConfiguration, null);
        panConfiguration.setLayout(null);

        // ComboBox for Kettler
        cbxPort = new JComboBox<String>();
        cbxPort.setFont(new Font("Tahoma", Font.PLAIN, 24));
        cbxPort.setBounds(734, 5, 247, 49);
        panConfiguration.add(cbxPort);

        // Button-Connection
        JButton btnConnect = new JButton("Connect");
        btnConnect.setFont(new Font("Tahoma", Font.PLAIN, 24));
        btnConnect.setBounds(157, 7, 137, 49);
        btnConnect.addActionListener(new ActionListener() {
            
            
            public void actionPerformed(ActionEvent arg0) {
                
                try {
                    bike1 = new KettlerBikeConnector();
                    bike1.connect(cbxPort.getSelectedItem().toString(), new KettlerBikeListener() {
                        @Override
                        public void bikeAck() {
                            switch (listener.state) {
                            case hello:
                                listener.state = State.connected;
                                break;
                            case reset:
                                listener.state = State.hello;
                                break;
                            case connected:
                                log("connection successful");
                                break;
                            case notConnected:
                                log("not connected");
                                break;
                            }
                        }

                        @Override
                        public void bikeData(DataRecord data) {
                            //Sending the Ergometer velcoity every 1000ms to the 
                            panBSim.setErgometerVelocity(data.getSpeed() / 10);
                            panBSim.setErgometerRPM(data.getPedalRpm());
                            panBSim.setTrueDataHere(true);
                            
                            double power = panBSim.getTraveledDistance();
                            chd.setPower(power);

                            //getPower und dann set hier die Ergometer widerstand
                            try {
                                bike1.sendSetPower(panBSim.getErgometerPower());
                                
                            } catch (IOException ignored) {
                                System.out.println("ignored");
                            }
                        }

                        @Override
                        public void bikeDestPowerChanged(int power) {
                            log("dest power: " + power);
                        }

                        @Override
                        public void bikeError() {
                            log("error1");
                        }
                    });
                } catch (Exception e) {
                    log(e.getMessage());
                }
            }
        });
        panConfiguration.add(btnConnect);

        // Button-Start
        JButton btnStart = new JButton("Start");
        btnStart.setFont(new Font("Tahoma", Font.PLAIN, 24));
        btnStart.setBounds(304, 7, 137, 49);
        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                try {
                    listener = new TimerListener(bike1);
                    timerBike = new Timer(UPDATE_MS, listener);
                    timerBike.start();
                    
                    tabPane.setSelectedComponent(panSimulator); // switch to GamePanel
                    panBSim.startSimulate();
                    
                } catch (Exception e) {
                    log(e.getMessage());
                }
            }
        });
        panConfiguration.add(btnStart);

        // Button-Scan
        JButton btnScan = new JButton("Scan");
        btnScan.setFont(new Font("Tahoma", Font.PLAIN, 24));
        btnScan.setBounds(10, 7, 137, 49);
        btnScan.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

                Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers(); // list of named

                while (portList.hasMoreElements()) {
                    CommPortIdentifier portId = (CommPortIdentifier) portList.nextElement();
                    if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                        cbxPort.addItem(portId.getName());
                        if (portId.isCurrentlyOwned()) {
                            log("Port " + portId.getName() + " is already open");
                        }
                    }
                }
            }

        });
        panConfiguration.add(btnScan);

        // Status displays information regarding connection
        lblStatus = new JTextPane();
        lblStatus.setText(
                "Anweisung:\r\n\t1) W\u00E4hle ein Lebensmittel aus der Food-Item Combobox aus\r\n\t2) Dr\u00FCcke den Scan-Button und w\u00E4hle den Port aus der Port Combobox aus\r\n\t3) Dr\u00FCcke den Connect-Button, um die Ger\u00E4te zu verbinden\r\n\t4) Dr\u00FCcke den Start-Button, um die Anwendung zu starten\r\n\t5) Warte auf das akustische Signal des Ergometer\r\n\t6) Beginne zu treten");
        lblStatus.setFont(new Font("Tahoma", Font.PLAIN, 24));
        lblStatus.setBounds(10, 125, 971, 229);
        lblStatus.setDisabledTextColor(Color.BLACK);
        lblStatus.setSelectionColor(new Color(51, 153, 255));
        panConfiguration.add(lblStatus);

        // FH Logo
        JLabel lblLogo = new JLabel("");
        lblLogo.setBounds(10, 365, 971, 430);

        try {
            File in = new File("FHLogo.png");
            Image logo = ImageIO.read(in);
            Image scaledLogo = logo.getScaledInstance(lblLogo.getWidth(), lblLogo.getHeight(), Image.SCALE_SMOOTH);

            ImageIcon iconLogo = new ImageIcon(scaledLogo);
            lblLogo.setIcon(iconLogo);
        } catch (IOException e2) {
            e2.printStackTrace();
        }

        panConfiguration.add(lblLogo);

        // Labels
        JLabel lblPort = new JLabel("Port:");
        lblPort.setFont(new Font("Tahoma", Font.PLAIN, 24));
        lblPort.setBounds(600, 5, 124, 49);
        panConfiguration.add(lblPort);

        //-----------------------------------------------------------------------------XXX
        //Tab Bike Simulator
        BorderLayout bdl = new BorderLayout();
                
        panSimulator = new JPanel();
        tabPane.addTab("Bike Simulator", null, panSimulator, null);
        panSimulator.setLayout(bdl);
        
        
        
        //Panel Bike Simulator
        //panBSim = new PanelBikeSimulator();
        //panBSim.setBorder(BorderFactory.createLineBorder(Color.black));
        panSimulator.add(chd.getContentPane(), bdl.NORTH);

    }

    /**
     * To log information
     * 
     * @param str String that is shown
     */
    private void log(String str) {
        lblStatus.setText(lblStatus.getText() + str + "\n");
    }
}

And this class belongs to my chart that I want to move to any location in my JPanel.

public class CrosshairDemo extends JFrame {
    
    private static double POWER = 0.0;
    
    public void setPower(double power) {
        POWER = power;
    }
    
    public CrosshairDemo() {
        super();
        this.setContentPane(new CrosshairDemo.MyDemoPanel());
    }
    

    public static class MyDemoPanel extends JPanel implements Runnable {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        Thread t = new Thread((Runnable) this);
  
        private TimeSeries series;
        private final ChartPanel chartPanel;
        private final JFreeChart chart = this.createChart();

        public MyDemoPanel() {
            super(new BorderLayout());

            this.chartPanel = new ChartPanel(this.chart);
            this.chartPanel.setPreferredSize(new Dimension(200, 550));
            this.chartPanel.setLocation(getWidth() + 50, getHeight() + 30);
            this.chartPanel.setDomainZoomable(true);
            this.chartPanel.setRangeZoomable(true);

            this.add(this.chartPanel);
            
            t.start();
        }

        private JFreeChart createChart() {
            XYDataset dataset1 = this.createDataset("Random 1", 100.0D, new Minute(), 200);
            JFreeChart chart1 = ChartFactory.createTimeSeriesChart("Crosshair Demo 1", "Time of Day", "Value", dataset1);
            XYPlot plot = (XYPlot)chart1.getPlot();
            plot.setOrientation(PlotOrientation.VERTICAL);
            plot.setDomainCrosshairVisible(true);
            plot.setDomainCrosshairLockedOnData(false);
            plot.setRangeCrosshairVisible(false);
            
            return chart1;
        }

        private XYDataset createDataset(String name, double base, RegularTimePeriod start, int count) {
            this.series = new TimeSeries(name);
            RegularTimePeriod period = start;
            double value = base;

            for(int i = 0; i < count; ++i) {
                this.series.add(period, value);
                period = period.next();
                value *= 1.0D + (Math.random() - 0.495D) / 10.0D;
            }

            TimeSeriesCollection dataset = new TimeSeriesCollection();
            dataset.addSeries(this.series);
            return dataset;
        }

        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(true) {
                int value = (int) POWER; //this.slider.getValue();
                XYPlot plot = (XYPlot)this.chart.getPlot();
                ValueAxis domainAxis = plot.getDomainAxis();
                Range range = domainAxis.getRange();
                double c = domainAxis.getLowerBound() + (double)value / 100.0D * range.getLength();
                plot.setDomainCrosshairValue(c);
            }
        }
        
    }

Right now it's "attached" to the top (NORTH) of my JPanel:

Current chart position:

https://i.stack.imgur.com/GXzw2.png

I would appreciate any help, because I have no more idea how to position this chart freely, therefore, I need your help guys.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Ivo95
  • 1
  • 1
    Why do you want a main JPanel with lots of empty space so you can position a JFreeChart JPanel anywhere in the main JPanel? What is the purpose behind this request? Create a [mre] that we can copy into our IDE and test without any of the JFreeChart code. – Gilbert Le Blanc Apr 06 '21 at 20:08
  • 1
    *how to position this chart freely,* - we have no idea what that means. That is not how layout management is done is Swing. Typically you use descriptions like: 1) centered horizontally, 2) centered vertically or 3) centered both horizontally and vertically.4) something else? Then once you have the proper requirement you use the appropriate layout manager. – camickr Apr 06 '21 at 20:25
  • 1
    This is no different from using a `JPanel` with a custom size and background color, the issue isn't related to `JFreeChart` but to Swing's layout management. Why would you want to position the chart anywhere? – Frakcool Apr 06 '21 at 21:42
  • It's possible to add an `EmptyBorder` that nudges a component up / down, left or right within the layout & constraint to which it is added. It would also be possible to offer the user spinners to adjust that at run-time. Having said that, like others replying, I don't really understand what the purpose of this is, and especially the advantage of allowing the user to reposition the component. Voted to close on the basis that you need to explain the purpose of this better. – Andrew Thompson Apr 07 '21 at 04:07
  • @AndrewThompson Hello, I just want to place the chart for example 50px to the right and 50 pixel down. My goal is to create a GUI for my simulator. – Ivo95 Apr 07 '21 at 16:07
  • So how'd you go trying to use an `EmptyBorder`? Show your attempt. BTW - opened this as I started my day, probably around 18 hours ago. But since this is not a help desk, I thought I'd wait to see what you had progressed to after the advice re using a border. You really should try things out when people suggest them. – Andrew Thompson Apr 08 '21 at 16:14
  • @AndrewThompson Already did, thank you. Case closed. – Ivo95 Apr 09 '21 at 14:50
  • Also consider enabling suitable controls, mentioned [here](https://stackoverflow.com/a/44151032/230513). – trashgod Apr 09 '21 at 17:46

0 Answers0