Jump to content
Frequently Asked Questions
  • Are you not able to open the client? Try following our getting started guide
  • Still not working? Try downloading and running JarFix
  • Help! My bot doesn't do anything! Enable fresh start in client settings and restart the client
  • How to purchase with PayPal/OSRS/Crypto gold? You can purchase vouchers from other users
  • GridPainter Paint Utility Class


    runehalberd

    Recommended Posts

    I wanted to make a simple Paint utility that is customizable and easy to use. This tool will create a grid structure full of cells, each of which can contain text such as script run time, xp gained, script status, etc. You define the layout of the grid, set the style of the cells, and can update them as your script runs. Note that this was originally written in Kotlin and the Java code is untested and auto-generated so you may have to do some work converting it to Java 🙂

    image.png.a35114942edf9d0d2ba325d01bcd4804.png

    Usage

     Kotlin

    Spoiler
    import org.dreambot.api.script.AbstractScript
    import util.gridpainter.GridPainter
    import java.awt.Graphics2D
    
    class Main : AbstractScript() {
    
        private val gridPainter = GridPainter()
    
        override fun onStart() {
            // Create a cell named Status on row 1 that spans 2 columns
            gridPainter.addCell(
                Cell(
                    name = "Status",
                    rowNum = 1,
                    span = 2,
                    data = "Logging in..."
                )
            )
            // Create a cell named Time on row 2 that spans 1 column
            gridPainter.addCell(
                Cell(
                    name = "Time",
                    rowNum = 2,
                    data = timer.getTime(),
                    span = 1,
                    prefixWithName = false,
                    font = Font("Arial", Font.PLAIN, 10)
                )
            )
        }
    
        override fun onLoop(): Int {
            // Update the Status cell
            gridPainter.updateCell("Status", "Script has started.")
        }
    
        override fun onPaint(graphics: Graphics2D?) {
            // Do any regular cell updating 
            gridPainter.updateCell("Time", data = timer.getTime())
            // Call draw() to render the grid
            gridPainter.draw(graphics!!)
        }
    }

     

    Java

    Spoiler
    import java.awt.Font;
    import java.awt.Graphics2D;
    
    public class Main extends AbstractScript {
        private GridPainter gridPainter = new GridPainter();
    
        @Override
        public void onStart() {
            // Create a cell named Status on row 1 that spans 2 columns
            gridPainter.addCell(
                new Cell(
                    "Status",
                    2,
                    "Logging in..."
                )
            );
            // Create a cell named Time on row 2 that spans 1 column
            gridPainter.addCell(
                new Cell(
                    "Time",
                    2,
                    timer.getTime(),
                    1,
                    false,
                    new Font("Arial", Font.PLAIN, 10)
                )
            );
        }
    
        @Override
        public int onLoop() {
            // Update the Status cell
            gridPainter.updateCell("Status", "Script has started.");
            return 0;
        }
    
        @Override
        public void onPaint(Graphics2D graphics) {
            // Do any regular cell updating 
            gridPainter.updateCell("Time", timer.getTime());
            // Call draw() to render the grid
            gridPainter.draw(graphics);
        }
    }

     

     

    These are the customizable properties:

    GridPainter:

    • show - toggle display on/off
    • x - left position of the grid
    • y - top position of the grid
    • cellWidth
    • cellHeight
    • cellBorderColor - color of the lines that border each cell

    Cell:

    • name - name of the cell used for indexing and updating/removing
    • data - the string to display in the cell
    • prefixWithName - if true, will prefix the display string with "$name: "
    • bgColor - background color of the cell
    • textColor
    • font - text Font() object
    • span - int for how many columns this cell will span

    Sources

    GridPainter.kt

    Spoiler
    package util.gridpainter
    
    import java.awt.Color
    import java.awt.Font
    import java.awt.Graphics2D
    import java.util.LinkedList
    
    class GridPainter(
        var show: Boolean = true,
        var x: Double = 20.0,
        var y: Double = 20.0,
        var cellWidth: Double = 110.0,
        var cellHeight: Double = 25.0,
        var cellBorderColor: Color = Color.WHITE,
        private val grid: MutableList<LinkedList<Cell>> = mutableListOf()
    ) {
    
        companion object {
            val GRAY = Color(70, 61, 50, 156)
            val RED = Color(255, 61, 50, 156)
            val GREEN = Color(70, 255, 50, 156)
            val WHITE = Color(255, 255, 255, 156)
            val font = Font("Arial", Font.PLAIN, 14)
        }
    
        fun draw(g: Graphics2D) {
            if (show) {
                var x = this.x
                var y = this.y
                for (row in grid) {
                    for (cell in row) {
                        cell.draw(g, x, y, cellWidth, cellHeight, cellBorderColor)
                        x += cellWidth
                    }
                    x = this.x
                    y += cellHeight
                }
            }
        }
    
        fun addCell(cell: Cell) {
            // Create rows up to rowNum if they don't exist yet
            if (grid.size < cell.rowNum) {
                grid.addAll(List(cell.rowNum - grid.size) { LinkedList() })
            }
            grid[cell.rowNum - 1].add(cell)
        }
    
        fun updateCell(
            name: String,
            data: String? = null,
            prefixWithName: Boolean? = null,
            bgColor: Color? = null,
            textColor: Color? = null,
            font: Font? = null,
            span: Int? = null
        ) {
            val cell = findCell(name)
            if (cell != null) {
                if (data != null) {
                    cell.data = data
                }
                if (prefixWithName != null) {
                    cell.prefixWithName = prefixWithName
                }
                if (bgColor != null) {
                    cell.bgColor = bgColor
                }
                if (textColor != null) {
                    cell.textColor = textColor
                }
                if (font != null) {
                    cell.font = font
                }
                if (span != null) {
                    cell.span = span
                }
            }
        }
    
        fun removeCell(name: String) {
            for (row in grid) {
                row.remove(findCell(name))
            }
        }
    
        private fun findCell(name: String): Cell? {
            for (row in grid) {
                val cell = row.find { it.name == name }
                if (cell != null) {
                    return cell
                }
            }
    
            return null
        }
    }

    Cell.kt

    Spoiler
    package util.gridpainter
    
    import util.gridpainter.GridPainter.Companion.GRAY
    import util.gridpainter.GridPainter.Companion.WHITE
    import java.awt.Color
    import java.awt.Font
    import java.awt.Graphics2D
    import java.awt.geom.Rectangle2D
    
    data class Cell(
        val name: String,
        val rowNum: Int,
        var data: String,
        var span: Int = 1,
        var prefixWithName: Boolean = true,
        var bgColor: Color = GRAY,
        var textColor: Color = WHITE,
        var font: Font = Font("Arial", Font.PLAIN, 10)
    ) {
        fun draw(g: Graphics2D, x: Double, y: Double, cellWidth: Double, cellHeight: Double, cellBorderColor: Color) {
            val w = cellWidth * span
            val text = if (prefixWithName) "$name: $data" else data
            val rect = Rectangle2D.Double(x, y, w, cellHeight)
            g.color = bgColor
            g.fill(rect)
            g.color = cellBorderColor
            g.draw(rect)
    
            g.font = font
            val fm = g.fontMetrics
            val textx = x + ((w - fm.stringWidth(text)) / 2)
            val texty = y + (((cellHeight - fm.height) / 2) + fm.ascent)
            g.drawString(text, textx.toFloat(), texty.toFloat())
        }
    }

     GridPainter.java

    Spoiler
    package util.gridpainter;
    
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics2D;
    import java.util.LinkedList;
    import java.util.List;
    
    public class GridPainter {
        private boolean show;
        private double x;
        private double y;
        private double cellWidth;
        private double cellHeight;
        private Color cellBorderColor;
        private List<LinkedList<Cell>> grid;
    
        public static final Color GRAY = new Color(70, 61, 50, 156);
        public static final Color RED = new Color(255, 61, 50, 156);
        public static final Color GREEN = new Color(70, 255, 50, 156);
        public static final Color WHITE = new Color(255, 255, 255, 156);
        public static final Font font = new Font("Arial", Font.PLAIN, 14);
    
        public GridPainter(boolean show, double x, double y, double cellWidth, double cellHeight, Color cellBorderColor) {
            this.show = show;
            this.x = x;
            this.y = y;
            this.cellWidth = cellWidth;
            this.cellHeight = cellHeight;
            this.cellBorderColor = cellBorderColor;
            this.grid = new LinkedList<>();
        }
    
        public void draw(Graphics2D g) {
            if (show) {
                double x = this.x;
                double y = this.y;
                for (LinkedList<Cell> row : grid) {
                    for (Cell cell : row) {
                        cell.draw(g, x, y, cellWidth, cellHeight, cellBorderColor);
                        x += cellWidth;
                    }
                    x = this.x;
                    y += cellHeight;
                }
            }
        }
    
        public void addCell(Cell cell) {
            // Create rows up to rowNum if they don't exist yet
            if (grid.size() < cell.getRowNum()) {
                grid.addAll(new ArrayList<>(cell.getRowNum() - grid.size()));
            }
            grid.get(cell.getRowNum() - 1).add(cell);
        }
    
        public void updateCell(String name, String data, Boolean prefixWithName, Color bgColor, Color textColor, Font font, Integer span) {
            Cell cell = findCell(name);
            if (cell != null) {
                if (data != null) {
                    cell.setData(data);
                }
                if (prefixWithName != null) {
                    cell.setPrefixWithName(prefixWithName);
                }
                if (bgColor != null) {
                    cell.setBgColor(bgColor);
                }
                if (textColor != null) {
                    cell.setTextColor(textColor);
                }
                if (font != null) {
                    cell.setFont(font);
                }
                if (span != null) {
                    cell.setSpan(span);
                }
            }
        }
    
        public void removeCell(String name) {
            for (LinkedList<Cell> row : grid) {
                row.remove(findCell(name));
            }
        }
    
        private Cell findCell(String name) {
            for (LinkedList<Cell> row : grid) {
                for (Cell cell : row) {
                    if (cell.getName().equals(name)) {
                        return cell;
                    }
                }
            }
            return null;
        }
    }
    

    Cell.java

    Spoiler
    package util.gridpainter;
    
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics2D;
    import java.awt.geom.Rectangle2D;
    
    public class Cell {
        private String name;
        private int rowNum;
        private String data;
        private int span;
        private boolean prefixWithName;
        private Color bgColor;
        private Color textColor;
        private Font font;
    
        public Cell(String name, int rowNum, String data, int span, boolean prefixWithName, Color bgColor, Color textColor, Font font) {
            this.name = name;
            this.rowNum = rowNum;
            this.data = data;
            this.span = span;
            this.prefixWithName = prefixWithName;
            this.bgColor = bgColor;
            this.textColor = textColor;
            this.font = font;
        }
    
        public void draw(Graphics2D g, double x, double y, double cellWidth, double cellHeight, Color cellBorderColor) {
            double w = cellWidth * span;
            String text = prefixWithName ? name + ": " + data : data;
            Rectangle2D rect = new Rectangle2D.Double(x, y, w, cellHeight);
            g.setColor(bgColor);
            g.fill(rect);
            g.setColor(cellBorderColor);
            g.draw(rect);
            g.setFont(font);
            java.awt.FontMetrics fm = g.getFontMetrics();
            double textx = x + ((w - fm.stringWidth(text)) / 2);
            double texty = y + (((cellHeight - fm.getHeight()) / 2) + fm.getAscent());
            g.drawString(text, (float) textx, (float) texty);
        }
    }

     

    Edited by runehalberd
    Link to comment
    Share on other sites

    • 4 weeks later...

    Great initiative!
    Was not working straight out of the box on java, but I made some modifications:

    image.png.aa3b80066e7b9dfa4a7a3fae96d2a5e3.png

     

    Main.Java

    public class Main extends TreeScript {
        private Timer timer;
        private long startTime;
        private GridPainter gridPainter = new GridPainter(true, 5, 5, 100, 35, new Color(255, 255, 255, 225));
    
        public static String formatElapsedTime(long milliseconds) {
            long seconds = milliseconds / 1000;
            long hours = seconds / 3600;
            long minutes = (seconds % 3600) / 60;
            long remainingSeconds = seconds % 60;
    
            return String.format("%02d:%02d:%02d", hours, minutes, remainingSeconds);
        }
    
        @Override
        public void onPause() {
            if (timer != null) {
                timer.pause();
            }
        }
    
        @Override
        public void onStart() {
    
            timer = new Timer();
            startTime = System.currentTimeMillis();
            timer.start();
    
            gridPainter.addCell(
                    new Cell(
                            "Time",
                            1,
                            "52",
                            1,
                            false,
                            new Color(255, 255, 255, 255),
                            new Color(255, 255, 255, 255)
                    )
            );
            gridPainter.addCell(
                    new Cell(
                            "Woodcutting EXP",
                            2,
                            "0",
                            2,
                            false,
                            new Color(255, 255, 255, 255),
                            new Color(255, 255, 255, 255)
                    )
            );
            gridPainter.addCell(
                    new Cell(
                            "Fletching EXP",
                            3,
                            "0",
                            2,
                            false,
                            new Color(255, 255, 255, 255),
                            new Color(255, 255, 255, 255)
                    )
            );
    
        }
    
        @Override
        public int onLoop() {
            if (timer != null && timer.isPaused()) {
                timer.resume();
            }
            return this.getRoot().onLoop();
        }
    
        @Override
        public void onPaint(Graphics2D graphics) {
            gridPainter.updateCell("Time", formatElapsedTime(timer.elapsed()));
            gridPainter.updateCell("Woodcutting EXP", String.valueOf(SkillTracker.getGainedExperience(Skill.WOODCUTTING)) + "exp");
            gridPainter.updateCell("Fletching EXP", String.valueOf(SkillTracker.getGainedExperience(Skill.FLETCHING)) + "exp");
            gridPainter.draw(graphics);
        }
    }

     

    ScriptPaint.Cell.java

    package ScriptPaint;
    
    import java.awt.*;
    import java.awt.geom.Rectangle2D;
    
    public class Cell {
        public static final Font font = new Font("Arial", Font.PLAIN, 14);
        private String name;
        private int rowNum;
        private String data;
        private int span;
        private boolean prefixWithName;
        private Color bgColor;
        private Color textColor;
    
        public Cell(String name, int rowNum, String data, int span, boolean prefixWithName, Color bgColor, Color textColor) {
            this.name = name;
            this.rowNum = rowNum;
            this.data = data;
            this.span = span;
            this.prefixWithName = prefixWithName;
            this.bgColor = bgColor;
            this.textColor = textColor;
        }
    
        public void draw(Graphics2D g, double x, double y, double cellWidth, double cellHeight, Color cellBorderColor) {
            double w = cellWidth * span;
            String text = prefixWithName ? name + ": " + data : data;
            Rectangle2D.Double rect = new Rectangle2D.Double(x, y, w, cellHeight);
            g.setColor(new Color(0, 0, 0, 100));
            g.fill(rect);
            g.setColor(cellBorderColor);
            g.draw(rect);
    
            g.setFont(font);
            FontMetrics fm = g.getFontMetrics();
            float textX = (float) (x + ((w - fm.stringWidth(text)) / 2));
            float textY = (float) (y + (((cellHeight - fm.getHeight()) / 2) + fm.getAscent()));
            g.setColor(Color.WHITE); //text color
            g.drawString(text, textX, textY);
        }
    
        public String getName() {
            return name;
        }
    
        public int getRowNum() {
            return rowNum;
        }
    
    
        public void setData(String data) {
            this.data = data;
        }
    
    
        public void setPrefixWithName(boolean prefixWithName) {
            this.prefixWithName = prefixWithName;
        }
    
    
        public void setBgColor(Color bgColor) {
            this.bgColor = bgColor;
        }
    
    
        public void setTextColor(Color textColor) {
            this.textColor = textColor;
        }
    
    
    }

    ScriptPaint.GridPainter.java

    package ScriptPaint;
    
    import org.dreambot.api.utilities.Logger;
    
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics2D;
    import java.util.LinkedList;
    import java.util.List;
    
    public class GridPainter {
        public static final Color GRAY = new Color(70, 61, 50, 156);
        public static final Color RED = new Color(255, 61, 50, 156);
        public static final Color GREEN = new Color(70, 255, 50, 156);
        public static final Color WHITE = new Color(255, 255, 255, 156);
        public static final Font font = new Font("Arial", Font.PLAIN, 14);
        private boolean show;
        private double x;
        private double y;
        private double cellWidth;
        private double cellHeight;
        private Color cellBorderColor;
        private List<LinkedList<Cell>> grid;
    
        public GridPainter(boolean show, double x, double y, double cellWidth, double cellHeight, Color cellBorderColor) {
            this.show = show;
            this.x = x;
            this.y = y;
            this.cellWidth = cellWidth;
            this.cellHeight = cellHeight;
            this.cellBorderColor = cellBorderColor;
            this.grid = new LinkedList<>();
        }
    
        public void draw(Graphics2D g) {
            if (show) {
                double x = this.x;
                double y = this.y;
                for (LinkedList<Cell> row : grid) {
                    for (Cell cell : row) {
                        cell.draw(g, x, y, cellWidth, cellHeight, cellBorderColor);
                        x += cellWidth;
                    }
                    x = this.x;
                    y += cellHeight;
                }
            }
        }
    
        public void addCell(Cell cell) {
            int targetRowIndex = cell.getRowNum() - 1;
            // Ensure the grid has enough rows
            while (grid.size() <= targetRowIndex) {
                grid.add(new LinkedList<>());
            }
            // Add the cell to the appropriate row
            grid.get(targetRowIndex).add(cell);
        }
    
        public void updateCell(String name, String data) {
            Cell cell = findCell(name);
            if (cell != null) {
                if (data != null) {
                    cell.setData(data);
                    cell.setPrefixWithName(true);
                    cell.setBgColor(new Color(70, 61, 50, 156));
                    cell.setTextColor(new Color(255, 0, 0, 255));
                }
            }
        }
    
        public void removeCell(String name) {
            for (LinkedList<Cell> row : grid) {
                row.remove(findCell(name));
            }
        }
    
        private Cell findCell(String name) {
            for (LinkedList<Cell> row : grid) {
                for (Cell cell : row) {
                    if (cell.getName().equals(name)) {
                        return cell;
                    } else {
                        Logger.log("UABLE TO FIND CELL " + name);
                    }
                }
            }
            return null;
        }
    }

    The updated code is arguably less clean and worse than originally proposed. but it works :)

     

    Edited by ImLife
    added formatting to java code
    Link to comment
    Share on other sites

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now
    ×
    ×
    • Create New...

    Important Information

    We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.