Table visuals

Yes, @moti is right, you can achieve table rendering using a custom Figure.

Attached you will find a demo study to help get you started.

Some key considerations for your implementation:
  1. Three-method contract - isVisible() gates everything; layout() measures and caches geometry; draw() only paints using cached values. The framework calls them in this order.
  2. Never measure in draw() - All FontMetrics / sizing work goes in layout(). The draw() method should be as fast as possible since it runs on every repaint. To get FontMetrics for text measurement, create a temporary BufferedImage(1, 1, TYPE_INT_ARGB), call createGraphics(), set the font, grab metrics, and dispose(). Make sure draw() uses the same font via gc.setFont() so measurements match rendering.
  3. Column width algorithm - Seed each column width with its header text width, then iterate all data rows taking the max. Total table width = sum of column widths + padding between each.
  4. Positioning - ctx.getBounds() gives the visible chart rectangle. Anchor the table relative to that (center, bottom-right, etc.).
  5. Registration - In the study, call addFigure(new TableFigure()) once (e.g., in onBarUpdate() or after data arrives). The framework then calls the figure's lifecycle methods automatically.
  6. Text baseline - Graphics2D.drawString() draws at the text baseline, not the top. That's why the y-coordinate starts at tableY + rowH - 4 (row height minus a small descent offset).
  7. Thread safety with volatile — The study writes rows from the calculation thread; the figure reads it from the paint thread. volatile ensures safe publication of the array reference. layout() snapshots it into cachedRows so draw() works on a consistent dataset even if the study updates mid-paint.
  8. transient fields — Mark tableFigure and figureRegistered as transient since they shouldn't survive serialization. The framework may serialize studies; these get rebuilt on next use.
 

Attachments

Top