0

I am new to JFreeChart, and I don't understand how all the classes work together yet. I am trying to create a Gantt chart with custom labels and custom tooltip. The custom labels work (though I don't think I did it the proper clean way), but I don't get the custom tooltip to work.

After pressing on a button in another panel I send the required data (a date) I get from the database to the class that generates the gantt chart. With the date I got as a variable I get all the information for this date from the database and put it in the gantt chart.

This is how my gantt chart looks right now: enter image description here

my main class looks like that:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Connection;
import java.util.Calendar;
import javax.swing.*;

import info.clearthought.layout.TableLayout;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.category.IntervalCategoryDataset;
import org.jfree.data.gantt.Task;
import org.jfree.data.gantt.TaskSeries;
import org.jfree.data.gantt.TaskSeriesCollection;

public class Schichtplanner extends JFrame {
    private static final long serialVersionUID = 1L;
    double busX[] = new double[]{SchichtplannerConstants.GUI_BORDER, 250, TableLayout.FILL, TableLayout.FILL};
    double busY[] = new double[]{SchichtplannerConstants.GUI_BORDER, 35, SchichtplannerConstants.DISTANCE_BUTTONS, 35, SchichtplannerConstants.DISTANCE_BUTTONS, 35, SchichtplannerConstants.DISTANCE_BUTTONS, 35};

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                //System.setProperty("https.protocols", "TLSv1");
                try {
                    Schichtplanner frame = new Schichtplanner();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public Schichtplanner() {
        //JFrame frame = new JFrame("Schichtplanner");
        this.setTitle("Schichtplanungs-App");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setExtendedState(JFrame.MAXIMIZED_BOTH);

        JPanel panelMain = new JPanel();
        add(panelMain);

        panelMain.setLayout(new TableLayout(new double[][]{busX, busY}));

        JButton buttonMitarbeiterVerwalten = new JButton("Mitarbeiter verwalten");
        panelMain.add(buttonMitarbeiterVerwalten, "1,1,1,1"); // Adds Button to content pane of frame
        buttonMitarbeiterVerwalten.addActionListener( new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                //MitarbeiterVerwalten mitarbeiterVerwaltenFrame = new MitarbeiterVerwalten();
            }
        });

        JButton buttonAuftragVerwalten = new JButton("Auftrag verwalten");
        panelMain.add(buttonAuftragVerwalten, "1,3,1,3"); // Adds Button to content pane of frame
        buttonAuftragVerwalten.addActionListener( new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                //AuftragVerwalten auftragVerwaltenFrame = new AuftragVerwalten();
            }
        });

        JButton buttonSucheAuftrag = new JButton("Auftrag suchen");
        panelMain.add(buttonSucheAuftrag, "1,5,1,5"); // Adds Button to content pane of frame

        JButton buttonKalenderAnsicht = new JButton("Kalenderansicht");
        panelMain.add(buttonKalenderAnsicht, "1,7,1,7"); // Adds Button to content pane of frame
        buttonKalenderAnsicht.addActionListener( new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                try {
                    AuftragsÜbersicht auftragsÜbersicht = new AuftragsÜbersicht("2023-08-17");
                } catch (ParseException ex) {
                    ex.printStackTrace();
                }
            }
        });

        setVisible(true);
        panelMain.setVisible(true);
    }
}  

And my gantt chart class is like that:

import com.github.lgooddatepicker.components.DatePicker;
import info.clearthought.layout.TableLayout;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.labels.*;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.IntervalCategoryDataset;
import org.jfree.data.gantt.Task;
import org.jfree.data.gantt.TaskSeries;
import org.jfree.data.gantt.TaskSeriesCollection;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;

import org.jfree.chart.renderer.category.StandardBarPainter;

public class AuftragsÜbersicht extends JFrame {

private ArrayList<Calendar> auftragsBeginn, auftragsEnde;
private ArrayList<String> auftragsAdresse, auftragsPLZ, mitarbeiterVorname, mitarbeiterNachname;
private ArrayList<Integer> liegenschaftsnummer;

public AuftragsÜbersicht(String date) throws ParseException {
    double busX[] = new double[]{SchichtplannerConstants.GUI_BORDER, 250, TableLayout.FILL, TableLayout.FILL, SchichtplannerConstants.GUI_BORDER};
    double busY[] = new double[]{SchichtplannerConstants.GUI_BORDER, 35, 40, 35, SchichtplannerConstants.DISTANCE_BUTTONS, 35, 35, SchichtplannerConstants.DISTANCE_BUTTONS, 35, 35};
    auftragsBeginn = new ArrayList<>();
    auftragsEnde = new ArrayList<>();
    auftragsAdresse = new ArrayList<>();
    auftragsPLZ = new ArrayList<>();
    mitarbeiterVorname = new ArrayList<>();
    mitarbeiterNachname = new ArrayList<>();
    liegenschaftsnummer = new ArrayList<>();

    this.setTitle("Tagesübersicht Aufträge");
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    this.setSize(screenSize.width, screenSize.height);
    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    try
    {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (Exception e) {
        e.printStackTrace();
    }

    /********************************/
    // Create dataset
    IntervalCategoryDataset dataset = getCategoryDataset(date);

    // Create chart
    JFreeChart chart = ChartFactory.createGanttChart(date, "Mitarbeiter", "Zeitachse", dataset, false, true, false);
    chart.setBackgroundPaint(Color.white);

    //chart.setBorderVisible(false);
    CategoryPlot plot = (CategoryPlot) chart.getPlot();
    plot.setDomainGridlinePaint(Color.white);
    plot.setOutlinePaint(Color.white);
    plot.setBackgroundPaint(Color.white);
    //plot.setOutlineVisible(false);

    plot.getRenderer().setBaseToolTipGenerator( new MyToolTipGenerator( "{0}, {1}: ", DateFormat.getTimeInstance(DateFormat.SHORT)));

    ChartPanel panel = new ChartPanel(chart);
    setContentPane(panel);
    setVisible(true);

    /*******************************/
    setResizable(false);
}

private IntervalCategoryDataset getCategoryDataset(String date) throws ParseException {
    date = date + " 00:00:00.00000";
    Timestamp timestamp = Timestamp.valueOf(date);
    Timestamp timestamp2 = addDays(timestamp,1);

    /*try {
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3307/schichtplanung", "root", "admin");

        PreparedStatement st = (PreparedStatement) connection.prepareStatement("SELECT schichtplanung.auftrag.auftragsbeginn, schichtplanung.auftrag.auftragsende, schichtplanung.auftrag.auftragsadresse, schichtplanung.auftrag.auftragsplz, schichtplanung.auftrag.liegenschaftsnummer, schichtplanung.mitarbeiter.vorname, schichtplanung.mitarbeiter.nachname FROM schichtplanung.auftrag INNER JOIN schichtplanung.mitarbeiter ON schichtplanung.auftrag.mitarbeiterid=schichtplanung.mitarbeiter.mitarbeiterid WHERE schichtplanung.auftrag.auftragsbeginn >= ? AND schichtplanung.auftrag.auftragsbeginn < ?");
        st.setTimestamp(1, timestamp);
        st.setTimestamp(2, timestamp2);
        ResultSet rs = st.executeQuery();
        while (rs.next()) {
            Calendar calendar1 = Calendar.getInstance();
            calendar1.setTimeInMillis(rs.getTimestamp(1).getTime());
            getAuftragsBeginnList().add(calendar1);

            Calendar calendar2 = Calendar.getInstance();
            calendar2.setTimeInMillis(rs.getTimestamp(2).getTime());
            getAuftragsEndeList().add(calendar2);

            getAuftragsAdresseList().add(rs.getString(3));
            getAuftragsPLZList().add(rs.getString(4));
            getLiegenschaftsnummerList().add(rs.getInt(5));
            getMitarbeiterVornameList().add(rs.getString(6));
            getMitarbeiterNachnameList().add(rs.getString(7));
        }
        rs.close();
        st.close();
    } catch (SQLException sqlException) {
        sqlException.printStackTrace();
    }*/

    Calendar cal = Calendar.getInstance();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    cal.setTime(sdf.parse("2023-08-17 07:30:00"));// all done
    auftragsBeginn.add(cal);

    Calendar cal1 = Calendar.getInstance();
    SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    cal1.setTime(sdf1.parse("2023-08-17 15:30:00"));// all done
    auftragsEnde.add(cal1);

    auftragsAdresse.add("Ohmstraße 32");
    auftragsPLZ.add("45711");
    liegenschaftsnummer.add(1);
    mitarbeiterVorname.add("Michael");
    mitarbeiterNachname.add("Thompson");

    Calendar cal2 = Calendar.getInstance();
    SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    cal2.setTime(sdf2.parse("2023-08-17 09:00:00"));// all done
    auftragsBeginn.add(cal2);

    Calendar cal3 = Calendar.getInstance();
    SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    cal3.setTime(sdf3.parse("2023-08-17 16:30:00"));// all done
    auftragsEnde.add(cal3);

    auftragsAdresse.add("Fegestraße 5");
    auftragsPLZ.add("44623");
    liegenschaftsnummer.add(2);
    mitarbeiterVorname.add("Hasan");
    mitarbeiterNachname.add("Sekici");

    Calendar cal4 = Calendar.getInstance();
    SimpleDateFormat sdf4 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    cal4.setTime(sdf4.parse("2023-08-17 08:00:00"));// all done
    auftragsBeginn.add(cal4);

    Calendar cal5 = Calendar.getInstance();
    SimpleDateFormat sdf5 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    cal5.setTime(sdf5.parse("2023-08-17 17:30:00"));// all done
    auftragsEnde.add(cal5);

    auftragsAdresse.add("Sambaweg 10");
    auftragsPLZ.add("44141");
    liegenschaftsnummer.add(3);
    mitarbeiterVorname.add("Jon");
    mitarbeiterNachname.add("Schnee");

    TaskSeries series1 = new TaskSeries("Aufträge");
    for (int i = 0; i < auftragsAdresse.size(); i++) {
        series1.add(new Task(getMitarbeiterVornameList().get(i) + " " + getMitarbeiterNachnameList().get(i), getAuftragsBeginnList().get(i).getTime(), getAuftragsEndeList().get(i).getTime()));
        System.out.println(getMitarbeiterVornameList().get(i) + " " + getMitarbeiterNachnameList().get(i) + " BeginnZeit: " + getAuftragsBeginnList().get(i).getTime() + " EndeZeit: " + getAuftragsEndeList().get(i).getTime());
    }

    TaskSeriesCollection dataset = new TaskSeriesCollection();
    dataset.add(series1);
    return dataset;
}

public ArrayList<Calendar> getAuftragsBeginnList() {
    return auftragsBeginn;
}

public ArrayList<Calendar> getAuftragsEndeList() {
    return auftragsEnde;
}

public ArrayList<String> getAuftragsAdresseList() {
    return auftragsAdresse;
}

public ArrayList<String> getAuftragsPLZList() {
    return auftragsPLZ;
}

public ArrayList<String> getMitarbeiterVornameList() {
    return mitarbeiterVorname;
}

public ArrayList<String> getMitarbeiterNachnameList() {
    return mitarbeiterNachname;
}

public ArrayList<Integer> getLiegenschaftsnummerList() {
    return liegenschaftsnummer;
}

public Timestamp addDays(Timestamp date, int days) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);// w ww.  j ava  2  s  .co m
    cal.add(Calendar.DATE, days); //minus number would decrement the days
    return new Timestamp(cal.getTime().getTime());

}
}

class MyToolTipGenerator extends IntervalCategoryToolTipGenerator {

DateFormat format;

public MyToolTipGenerator(String value, DateFormat format) {
    super(value, format);
    this.format = format;
}

@Override
public String generateToolTip(CategoryDataset cds, int row, int col) {
    final String s = super.generateToolTip(cds, row, col);
    TaskSeriesCollection tsc = (TaskSeriesCollection) cds;
    StringBuilder sb = new StringBuilder(s);
    for (int i = 0; i < tsc.getSubIntervalCount(row, col); i++) {
        sb.append(format.format(tsc.getStartValue(row, col, i)));
        sb.append("-");
        sb.append(format.format(tsc.getEndValue(row, col, i)));
        sb.append(",");
    }
    sb.deleteCharAt(sb.length() - 1);
    return sb.toString();
}
}

I already tried some of the examples and solutions that were posted here but neither of them worked. Since I get several data from the db and store them all in an ArrayList, I want to show the specific related begin and end time (getAuftragsBeginnList and getAuftragsEndeList) in relation to the hovered datapoint.

NECben067
  • 427
  • 1
  • 4
  • 20
  • Why are you replacing the chart factory's renderer? What happens if you use the existing renderer and enable `tooltips`? You can customize it like [this](https://stackoverflow.com/a/15241250/230513) or substitute your own factory. – trashgod Aug 19 '23 at 17:57
  • At the beginning I did this for my custom labels, but I think I can just set them by plot.getRenderer() right? The example you sended me is confusing me. What are the parameters I need to insert in the MyTooltipGenerator Constructor? I want to show the parameters that are in my list? – NECben067 Aug 19 '23 at 20:01
  • The example I cited shows`MyToolTipGenerator`, a subclass of `IntervalCategoryToolTipGenerator`; your implementation of `generateToolTip()` should return your list. If this is unclear, please [edit] your question to include a [mre] that shows your revised approach; as I lack you database, please feel free to use the example cited. – trashgod Aug 19 '23 at 22:47
  • Also consider extending `IntervalCategoryDataset` in a manner similar to `JDBCCategoryDataset`; you can then leverage the message format described [here](https://stackoverflow.com/a/42052500/230513) in your own implementation of the `IntervalCategoryToolTipGenerator` method, `createItemArray()`. – trashgod Aug 20 '23 at 16:21
  • @trashgod I included now minimal reproducable code. I tried the example you sended me but again couldn't get it to work. I think I am missing something. I removed the new renderer and tried to set Tooltip as you suggested with MyToolTip but it did'nt show anything. In this reproducable example I set the things back so it is reproducable. – NECben067 Aug 22 '23 at 05:09
  • I don't see where you invoke `setBaseToolTipGenerator()`. – trashgod Aug 22 '23 at 21:52
  • @trashgod I removed it again so I could provide a working application. I used the setBaseTooltipGenerator as the example. I removed the new renderer completely and put the line 'plot.getRenderer().setBaseToolTipGenerator( new MyToolTipGenerator( "{0}, {1}: ", DateFormat.getTimeInstance(DateFormat.SHORT)));' and put it directly under the other plot commands – NECben067 Aug 23 '23 at 04:30
  • That _sounds_ right, but I can only guess; please [edit] your question to include a [mre] that shows your revised approach and focuses on tooltip rendering; note that neither I nor other readers have your database, so you'll need to mock that aspect; as `generateToolTip` and `generateLabel`, it may help to factor that into a separate method. – trashgod Aug 23 '23 at 17:00
  • @trashgod the code should already be reproducable since I exchanged the database with an arrayList so feel free to try it out. I also added the 'setTooltipGenerator()' part. I really don't know what to do in order for it to work. I tried many things now but it doesn't show any tooltip... – NECben067 Aug 25 '23 at 06:33
  • Sorry it's not working; I urge you to study the problem is isolation using the [mre] I previously cited, seen [here](https://stackoverflow.com/a/15241250/230513); verify that you understand how it works, and adapt it to your use. Sadly, your 300+ lines of code in _not_ minimal; one frame should be sufficient; due to spurious imports, I still cannot run it; but I'll examine it, and any updates you make, as time permits. – trashgod Aug 25 '23 at 22:56
  • If you later move to a current release of [tag:jfreechart], see the migration guide cited [here](https://stackoverflow.com/a/70398420/230513). – trashgod Aug 26 '23 at 11:39

0 Answers0