0

I was thinking about making a GUI with a text input field, and on the right have a bufferedImage, which updates on the input i enter in the "console". Is it possible to have these two in the same GUI?

What I was thinking about was this example: enter image description here

I've made a code where I only have a bufferedImage, but I want to add the left part of the image above, and I'm a bit stuck on how?

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.lang.Math;

// From SO post: https://stackoverflow.com/a/3325804/12989146
public class DirectDrawDemo extends JPanel {

    final private BufferedImage canvas;
    final private Color def_c = Color.BLACK; final private Color def_bg = Color.WHITE;

    public DirectDrawDemo(int width, int height) {
        canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        fillCanvas(def_bg);
        drawCircle(def_c,300,300,100);
    }

    public Dimension getPreferredSize() {
        return new Dimension(canvas.getWidth(), canvas.getHeight());
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.drawImage(canvas, null, null);
    }


    public void fillCanvas(Color c) {
        int color = c.getRGB();
        for (int x = 0; x < canvas.getWidth(); x++) {
            for (int y = 0; y < canvas.getHeight(); y++) {
                canvas.setRGB(x, y, color);
            }
        }
        repaint();
    }

    public void drawCircle(Color c, int x_center, int y_center, int r){
        // inspiration : https://www.gatevidyalay.com/mid-point-circle-drawing-algorithm/
        int x=r, y=0, p = 1-r;

        // checking for radius of circle
        if(r==0){
            drawPoint(x_center,y_center,c);
        }
        if(r<0)
            return;

        // initialising point p
        while(x>y){
            y++;
            if (p < 0) {
                p = p + 2 * y + 1;
            } else {
                x--;
                p = p+2*y-2*x+1;
            }
            //print all octaves
            drawPoint(x + x_center,y + y_center,c);     // 1. (x,y)
            drawPoint(y + x_center,x + y_center,c);     // 1. (y,x)
            drawPoint(y + x_center,-x + y_center,c);    // 4. (y,-x)
            drawPoint(x + x_center,-y + y_center,c);    // 4. (x,-y)
            drawPoint(-x + x_center,-y + y_center,c);   // 3. (-x,-y)
            drawPoint(-y + x_center,-x + y_center,c);   // 3. (-y,-x)
            drawPoint(-y + x_center,x + y_center,c);    // 2. (-y,x)
            drawPoint(-x + x_center,y + y_center,c);    // 2. (-x,y)
        }
        //show
        repaint();
    }
    void drawPoint(int x,int y,Color c){
        canvas.setRGB(x,y, c.getRGB());
    }



    public static void main(String[] args) {
        int width = 1280;
        int height = 940;
        JFrame frame = new JFrame("Direct draw demo");

        //JPanel panel = new JPanel();
        DirectDrawDemo panel2 = new DirectDrawDemo(width, height);
        //panel.setLayout(new GridLayout(0,1));

        //JLabel label1 = new JLabel();
        //label1.setText("Enter x");
        //JTextField textField1 = new JTextField();

        frame.add(panel2);
        //panel.add(label1);
        //panel.add(textField1);
        frame.pack();
        frame.setVisible(true);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }


}

EDIT

So I've tried what was told in the comments and it seems that i have the idea on how to place the different BorderLayouts as I want, but i have one issue now.. When I run my program The window is totaly BLANK (just white), but when I resize the window just a little or something everything pops up?

Here is my new code I've made:

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

public class GUI extends JPanel {
    final private BufferedImage canvas;
    final private Color def_c = Color.BLACK; final private Color def_bg = Color.WHITE;


    public static void main(String[] args){

        int width = 1280; int height = 720;

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(width, height);
        frame.setLayout(new BorderLayout(3,3));
        frame.setVisible(true);

        JPanel panel1 = new JPanel();
        JPanel panel2 = new JPanel();
        JPanel panel3 = new JPanel();

        panel1.setBackground(Color.red);
        panel2.setBackground(Color.green);
        panel3.setBackground(Color.yellow);

        panel1.setPreferredSize(new Dimension(200, 100));
        panel2.setPreferredSize(new Dimension(100, 100));
        panel3.setPreferredSize(new Dimension(100, 100));

        /*----- Sub panels -----*/
        GUI panel_Canvas = new GUI(width, height);

        //Add sub panels to this CENTER layout
        panel2.setLayout(new BorderLayout());

        //Adding to panel 2
        panel2.add(panel_Canvas, BorderLayout.CENTER);

        frame.add(panel1,BorderLayout.WEST);
        frame.add(panel2,BorderLayout.CENTER);
        frame.add(panel3,BorderLayout.SOUTH);


    }

    public GUI(int width, int height) {
        canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        fillCanvas(def_bg);
        int x0 = 0;
        int x1 = 500;
        int y0 = 0;
        int y1 = 300;
        //drawRect(Color.RED, 0, 0, width/2, height/2);
        drawLine(def_c, x0, y0, x1, y1);
        //drawLineRecInit(Color.yellow, x0, y0+2, x1, y1+2);
        drawCircle(def_c,300,300,100);
    }

    public Dimension getPreferredSize() {
        return new Dimension(canvas.getWidth(), canvas.getHeight());
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.drawImage(canvas, null, null);
    }


    public void fillCanvas(Color c) {
        int color = c.getRGB();
        for (int x = 0; x < canvas.getWidth(); x++) {
            for (int y = 0; y < canvas.getHeight(); y++) {
                canvas.setRGB(x, y, color);
            }
        }
        repaint();
    }


    // Implementation from Wikipedia: https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#All_cases
    public void drawLine(Color c, int x0, int y0, int x1, int y1)
    {
        int dx = Math.abs(x1-x0);
        int sx = x0 < x1 ? 1 : -1;
        int dy = -Math.abs(y1-y0);
        int sy = y0 < y1 ? 1 : -1;
        int err = dx + dy;  /* error value e_xy */
        while (true)   /* loop */
        {
            canvas.setRGB(x0, y0, c.getRGB());
            if (x0 == x1 && y0 == y1) break;
            int e2 = 2*err;
            if (e2 >= dy) /* e_xy+e_x > 0 */
            {
                err += dy;
                x0 += sx;
            }
            if (e2 <= dx) /* e_xy+e_y < 0 */
            {
                err += dx;
                y0 += sy;
            }
        }
        repaint();
    }

    public void drawLineRec(Color c, int x0, int y0, int x1, int y1, int dx, int dy, int err)
    {
        canvas.setRGB(x0, y0, c.getRGB());
        if(!(x0 == x1 && y0 == y1))
        {
            if((2*err) >= dy)
            {
                if((2*err) <= dx)
                {
                    drawLineRec(c, x0 + (x0 < x1 ? 1 : -1), y0 + (y0 < y1 ? 1 : -1), x1, y1, dx, dy, err + dx + dy);
                }
                else
                {
                    drawLineRec(c, x0 + (x0 < x1 ? 1 : -1), y0, x1, y1, dx, dy, err + dy);
                }
            }
            else if((2*err) <= dx)
            {
                drawLineRec(c, x0, y0 + (y0 < y1 ? 1 : -1), x1, y1, dx, dy, err + dx);
            }
        }
    }

    public void drawCircle(Color c, int x_center, int y_center, int r){
        // inspiration : https://www.gatevidyalay.com/mid-point-circle-drawing-algorithm/
        int x=r, y=0, p = 1-r;

        // checking for radius of circle
        if(r==0){
            drawPoint(x_center,y_center,c);
        }
        if(r<0)
            return;

        // initialising point p
        while(x>y){
            y++;
            if (p < 0) {
                p = p + 2 * y + 1;
            } else {
                x--;
                p = p+2*y-2*x+1;
            }
            //print all octaves
            drawPoint(x + x_center,y + y_center,c);     // 1. (x,y)
            drawPoint(y + x_center,x + y_center,c);     // 1. (y,x)
            drawPoint(y + x_center,-x + y_center,c);    // 4. (y,-x)
            drawPoint(x + x_center,-y + y_center,c);    // 4. (x,-y)
            drawPoint(-x + x_center,-y + y_center,c);   // 3. (-x,-y)
            drawPoint(-y + x_center,-x + y_center,c);   // 3. (-y,-x)
            drawPoint(-y + x_center,x + y_center,c);    // 2. (-y,x)
            drawPoint(-x + x_center,y + y_center,c);    // 2. (-x,y)
        }
        //show
        repaint();
    }
    void drawPoint(int x,int y,Color c){
        canvas.setRGB(x,y, c.getRGB());
    }

}

UPDATE

I added a button

enter image description here

Then I added the action listener in the GUI main enter image description here

On a button click this is called, but doesn't update the view?

enter image description here

the java view enter image description here

This is DrawCanvas enter image description here

Me NoLonely
  • 167
  • 11
  • 1
    That's what layout managers like [BorderLayout](https://docs.oracle.com/javase/tutorial/uiswing/layout/border.html) are used for. You can place the input field and the buttons in a separate `JPanel` and add it to the left of your `DirectDrawPanel` by adding it into the `frame` with `frame.add(inputPanel, BorderLayout.LINE_START);` – Thomas Kläger Mar 03 '21 at 09:47
  • Okay i will try that thanks :) – Me NoLonely Mar 03 '21 at 12:08
  • @ThomasKläger Hello again Thomas I've tried what you said, and updated the post in the EDIT section, but now I run into an issue where the page starts totally white (blank). But when I resize the window everything pops up? can't find the issue here – Me NoLonely Mar 04 '21 at 10:02
  • Never mind I moved the `frame.setVisible(true);` to the last line in the code, and how it works – Me NoLonely Mar 04 '21 at 10:05
  • @ThomasKläger maybe you know, but I've made a input-textfield where the user can type and I retrive the text as a string, lets say I type "1", and make a if statement to check for this specific "1", and inside the if I call a new `drawCircle(...)` how do I update my `BufferImage` with this new circle? because when I do it now and run the function nothing new is displayed? :) I maybe have to do an update or something, but thought my `repaint();` did that.. – Me NoLonely Mar 04 '21 at 11:52
  • I'm not sure where the problem is. To test I've added a button that draws an additional circle, and clicking on that button leads to an updated image that shows up. Are you sure that `drawCircle()` is called? – Thomas Kläger Mar 04 '21 at 20:38
  • @ThomasKläger It looks like the drawCircle is run, but nothing is shown, only if i hardcode a value before i add it to the frame. If you want to take a look at the project, to test type `1` into the textfield. I've postet it here, just type `we.` tl/t-lfIHLYwf8E – Me NoLonely Mar 04 '21 at 21:00
  • Sorry it's not the full project, only the files, just saw that.. hope you are still able to run/look at it – Me NoLonely Mar 04 '21 at 21:03
  • @ThomasKläger how did you even make it work with a button? – Me NoLonely Mar 04 '21 at 21:14
  • when i do the following `testButon.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { DrawCanvas p = new DrawCanvas(); p.drawCircle(300, 200, 100); } });` nothing happends, the repaint() is called inside drawCircle() – Me NoLonely Mar 04 '21 at 21:15
  • 1
    Ïf you create a `new DrawCanvas()` then you have to add it to the frame. I added `testButton.addActionListener(e -> panel_Canvas.drawCircle(Color.BLUE, 250, 250, 200));` to the `GUI.main()` method after the `GUI panel_Canvas = new GUI(width, height);` line. – Thomas Kläger Mar 04 '21 at 21:42
  • @ThomasKläger cant make it work still, sorry for that, I'm glad that you are trying, I've posted my pictures of what you told me, maybe you can spot what i do wrong? – Me NoLonely Mar 04 '21 at 22:04
  • @ThomasKläger if it helps, could you try to post you example? I have my project here: `wetransfer.com/downloads/f5d4281c5ec108bd9edb815ad27a217820210304212025/f96ce2` then you could reupload it, and i could look at how to? because I'm a bit lost, I've been sitting with the issue for too many hours haha – Me NoLonely Mar 04 '21 at 22:18

2 Answers2

1

I created the following GUI as a basis for what you want to accomplish.

Drawing Demo GUI

The two valid commands are "line" and "circle". The application generates random endpoints for a line and a random center point and radius for a circle.

So, here are the important points that I want you to take from the code I'm going to post.

  1. Always start your Swing application with a call to the SwingUtilities invokeLater method. This method ensures that your Swing components will be created and executed on the Event Dispatch Thread.

  2. Create an application model using plain Java getter / setter classes. I used this model to keep all the commands typed, so I could reproduce the drawing.

  3. Use Swing layout managers. I used a GridBagLayout to create the control panel on the left. The GridBagLayout is not the easiest layout to learn, but it's one of the most flexible.

Here's the complete runnable code. I made all the classes inner classes so I could paste this code as one block. Generally, you put separate classes in separate files.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class DrawingDemoGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new DrawingDemoGUI());
    }
    
    private DrawingModel drawingModel;
    
    private DrawingPanel drawingPanel;
    
    private JTextArea textArea;
    
    private JTextField inputField;
    
    public DrawingDemoGUI() {
        this.drawingModel = new DrawingModel();
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Drawing Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(createControlPanel(), BorderLayout.BEFORE_LINE_BEGINS);
        this.drawingPanel = new DrawingPanel(drawingModel);
        frame.add(drawingPanel, BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JPanel createControlPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.anchor = GridBagConstraints.LINE_START;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.gridwidth = 2;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weighty = 1.0;
        
        textArea = new JTextArea(10, 40);
        textArea.setEditable(false);
        textArea.setFont(new Font("monospaced", Font.PLAIN, 12));
        JScrollPane scrollPane = new JScrollPane(textArea);
        panel.add(scrollPane, gbc);
        
        gbc.gridwidth = 1;
        gbc.gridy++;
        gbc.weighty = 0.0;
        inputField = new JTextField(20);
        inputField.requestFocus();
        panel.add(inputField, gbc);
        
        gbc.gridx++;
        JButton button = new JButton("Submit");
        button.addActionListener(new SubmitListener());
        panel.add(button, gbc);
        
        return panel;
    }
    
    public void repaint() {
        drawingPanel.repaint();
    }
    
    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        private DrawingModel drawingModel;
        
        public DrawingPanel(DrawingModel drawingModel) {
            this.drawingModel = drawingModel;
            this.setBackground(Color.WHITE);
            this.setPreferredSize(new Dimension(400, 400));
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.BLACK);
            for (Command command : drawingModel.getCommands()) {
                if (command.getCommand().equalsIgnoreCase("line")) {
                    Point a = command.getOrigin();
                    Point b = command.getDestination();
                    g2d.drawLine(a.x, a.y, b.x, b.y);
                } else if (command.getCommand()
                        .equalsIgnoreCase("circle")) {
                    Point a = command.getOrigin();
                    int radius = command.getRadius();
                    int diameter = radius + radius;
                    g2d.drawOval(a.x - radius, a.y - radius, 
                            diameter, diameter);
                }
            }
        }
        
    }
    
    public class SubmitListener implements ActionListener {

        private boolean firstTimeSwitch = true;
        @Override
        public void actionPerformed(ActionEvent event) {
            String command = inputField.getText().trim();
            
            if (!firstTimeSwitch) {
                textArea.append(System.lineSeparator());
            }
            
            textArea.append(command);
            inputField.setText("");
            drawingModel.addCommand(command);
            repaint();
            
            firstTimeSwitch = false;
        }
        
    }
    
    public class DrawingModel {
        
        private List<Command> commands;
        
        private Random random;
        
        public DrawingModel() {
            this.commands = new ArrayList<>();
            this.random = new Random();
        }
        
        /**
         * We;re going to hard code a couple of commands. 
         * This is where you would define
         * your drawing commands.
         * 
         * @param command
         */
        public void addCommand(String commandString) {
            if (commandString.equalsIgnoreCase("line")) {
                Command command = new Command();
                command.setCommand(commandString);
                command.setOrigin(createRandomPoint(10, 380));
                command.setDestination(createRandomPoint(10, 380));
                commands.add(command);
            } else if (commandString.equalsIgnoreCase("circle")) {
                Command command = new Command();
                command.setCommand(commandString);
                command.setOrigin(createRandomPoint(50, 200));
                command.setRadius(random.nextInt(40));
                commands.add(command);
            }
        }
        
        private Point createRandomPoint(int offset, int range) {
            int x = random.nextInt(range) + offset;
            int y = random.nextInt(range) + offset;
            return new Point(x, y);
        }

        public List<Command> getCommands() {
            return commands;
        }
        
    }
    
    public class Command {
        
        private int radius;
        
        private Point origin;
        private Point destination;
        
        private String command;

        public int getRadius() {
            return radius;
        }

        public void setRadius(int radius) {
            this.radius = radius;
        }

        public Point getOrigin() {
            return origin;
        }

        public void setOrigin(Point origin) {
            this.origin = origin;
        }

        public Point getDestination() {
            return destination;
        }

        public void setDestination(Point destination) {
            this.destination = destination;
        }

        public String getCommand() {
            return command;
        }

        public void setCommand(String command) {
            this.command = command;
        }
        
    }

}
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
1

The frame will only redraw its child components. The ActionListener of your testbutton however creates its on drawCanvas that is never added to the frame and is therefore never included in the frames redraw.

Instead of that you will need one DrawCanvas that you add to the frame and that you do your redrawing on.

I've used the GUI class from your question and replaced the main() method with the following two methods:

public static void main(String[] args) {
    SwingUtilities.invokeLater(GUI::createFrame);
}

private static void createFrame() {
    int width = 1280; int height = 720;

    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(width, height);
    frame.setLayout(new BorderLayout(3,3));
    frame.setVisible(true);

    JPanel panel1 = new JPanel();
    JPanel panel2 = new JPanel();
    JPanel panel3 = new JPanel();

    panel1.setBackground(Color.red);
    panel2.setBackground(Color.green);
    panel3.setBackground(Color.yellow);

    panel1.setPreferredSize(new Dimension(200, 100));
    panel2.setPreferredSize(new Dimension(100, 100));
    panel3.setPreferredSize(new Dimension(100, 100));

    /*----- Sub panels -----*/
    GUI panel_Canvas = new GUI(width, height);

    //Add sub panels to this CENTER layout
    panel2.setLayout(new BorderLayout());

    //Adding to panel 2
    panel2.add(panel_Canvas, BorderLayout.CENTER);

    // *** These 3 lines below added *** //
    JButton b = new JButton("Circle");
    panel1.add(b);
    b.addActionListener(e -> panel_Canvas.drawCircle(Color.BLUE, 250, 250, 200));

    frame.add(panel1,BorderLayout.WEST);
    frame.add(panel2,BorderLayout.CENTER);
    frame.add(panel3,BorderLayout.SOUTH);
}

I've added just three lines to create a JButton with an ActionListener that draws an additional circle.

Or, with your updated code: replace the main method with this fragment:

static JButton testbutton = new JButton();
static DrawCanvas drawCanvas = new DrawCanvas();
static TextDemo = new TextDemo();

public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
        createAndShowGUI();
        testbutton.addActionListener(e -> drawCanvas.drawCircle(250, 250, 200));
    });
}

and replace part where you place the panels on the frame with

frame.add(testbutton, BorderLayout.NORTH);
frame.add(textDemo, BorderLayout.WEST);
frame.add(drawCanvas, BorderLayout.CENTER);
frame.add(panel3, BorderLayout.SOUTH;
Thomas Kläger
  • 17,754
  • 3
  • 23
  • 34