I have a half-working paint/turtle graphics program but I am having a few issues.
I am going to need to save the image that is drawn at some point - I know I need to use a BufferedImage but how do I go about this? I have attached a little bit of my code below.
In short I have a JFrame with a text field and a white JPanel below it. When commands are typed in by the user lines are drawing through another class and appear on the JPanel. I know I won't be able to save them off the JPanel to an image but have no understanding of how to implement a buffered image and what i would/wouldn't need to change.
Please be kind, I am new to programming and haven't finished some parts of my code yet.
Thanks in advance
public class Turtle2 extends JFrame implements ActionListener, KeyListener{
JMenuBar menuBar;
JMenu help, file;
JPanel panel, panel2;
JMenuItem newO, load, save, exitO, about;
JTextField text;
int savecounter = 0, newcounter = 1, part2I = 0;
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
int trigger = 1, turnleftconstant = 0, turnrightconstant =0, direction =0;
int col = 0;
public Turtle2() {
setLayout(new FlowLayout());
setSize(1000, 1000);
setTitle("Graphic");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//menu bar
//sets up general look of window
panel = new JPanel();
panel.setBackground(Color.darkGray);
//implements box layout
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
//sets up drawing area
panel2 = new JPanel();
panel2.setPreferredSize(new Dimension(500, 500));;
panel2.setBackground(Color.WHITE);
panel2.setBorder(BorderFactory.createLineBorder(Color.darkGray, 3));
//starting point on drawing area co-ordinates
x1 = 15; x2 = 15; y1 = 230; y2 =230;
//starting point implemented
LinePen first = new LinePen(x1, y1, x2, y2, col);
panel2.add(first);
//sets up user input text box
text = new JTextField(30);
//add action listener to text box - ready for input and details responses
text.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//retrieves user input
String actions = text.getText();
first.setVisible(true);
//commands from text
//add the command line textfeild to the interface
panel.add(text);
//uses border layout to set the layout of the interface
getContentPane().add(BorderLayout.NORTH, panel);
getContentPane().add(BorderLayout.CENTER, panel2);
//set the size of the interface
setSize(600,600);
//ensure the interface is visible
setVisible(true);
}
I would keep an array of all your lines, then iterate through them, and then use img.createGraphics() to draw your lines and other graphics.
Related
I'm trying to add a variable number of JPanels (each one containst 2 Label) inside another JPanel using the FlowLayout.
When there's too many panels added instead of going to the new row they disappear out of the border
I've tried many types of Layouts, setting sizes, maximussizes but nothing changes.
public class AlbumView extends javax.swing.JFrame
{
private Album A;
public AlbumView()
{
initComponents();
A = new Album();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int w = this.getSize().width;
int h = this.getSize().height;
int x = (dim.width-w)/2;
int y = (dim.height-h)/2;
this.setLocation(x, y);
pnlCategorie.setLayout(new FlowLayout(FlowLayout.TRAILING, 10, 10));
/*
Insert of many elements in the Album
*/
aggiornaAlbum();
}
public void aggiornaAlbum()
{
for(int i = 0; i < A.getDim(); i++)
{
Categoria c = A.getCategoria(i);
JPanel pnl = new JPanel();
pnl.setName(c.getNome());
JLabel lb1, lb2;
ImageIcon img = new ImageIcon(c.getPhoto(0).getImg(95, 95)); //da cambiare lo 0 con un numero casuale tra le foto disponibili
lb1 = new JLabel(img, JLabel.CENTER);
lb2 = new JLabel(c.getNome(), JLabel.CENTER);
pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
pnl.setBorder(BorderFactory.createLineBorder(Color.black));
pnl.add(lb1);
pnl.add(lb2);
//pnl.revalidate();
//pnl.repaint();
pnlCategorie.add(pnl);
}
//ADDED AFTER COMMENT, NOTHING CHANGED (but probably it's because i didn't get exaclty what to do
pnlCategorie.revalidate();
pnlCategorie.repaint();
}
pnlCategorie is created using NetBeans swing.
I expect that after the number of jpanels that fits the bigger jPanel the next one goes to a new line
Example of what is appearing (I'm using some exaple image, don't judge) :
I am currently learning how to use Swing in Java. When adding JTextFields, JLabels, or JButtons to a JPanel I usually do so in 4 lines such as this:
gbc.gridx = 0;
gbc.gridy = 0;
JTextField example = new JTextField("", 6);
p.add(example, gbc);
However I am trying to condense my code by making a method such as this:
public static void addTextField (JPanel p, GridBagConstraints gbc, String str, int x, int y, int len) {
gbc.gridx = x;
gbc.gridy = y;
JTextField tempTF = new JTextField(str, len);
p.add(tempTF, gbc);
}
and calling addTextField() in the main method such as this:
ClassName.addTextField(p2, gbc, "", 1, 1, 6);
The issue that I have is how to retrieve the text in the JTextField. Something like,
String str = example.getText();
or
String str2 = tempTF.getText();
which normally works, doesn't work anymore.
Any ideas on how I could solve this?
This is the full code I am working with before any answers:
/**
* This program creates two windows.
* Window #1 displays Hello World
* WIndow #2 prompts users to input information
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MessingWithSwing extends JFrame{
//Main Method
public static void main(String[] args) {
//makes the first window
MessingWithSwing window1 = new MessingWithSwing("Window #1", 300, 300);
//makes the second window with minimum dimensions
MessingWithSwing window2 = new MessingWithSwing("Window #2", 450, 300, 300, 300);
//GridBagConstraints allows the objects in each panel to be positioned in grid cordinates
GridBagConstraints gbc = new GridBagConstraints();
//sets the spaces between each grid position
gbc.insets = new Insets(10, 10, 10, 10);
//creates a JPanel that uses a grid layout
JPanel p1 = new JPanel(new GridBagLayout());
//adds the panel in the center of window1
window1.add(p1, BorderLayout.CENTER);
//sets the panel visible so it can correctly display the labels, textfields, and buttons
p1.setVisible(false);
//uses the method created below to add JLabels to p1
MessingWithSwing.addLabel(p1, gbc, "Hello", 0, 0);
MessingWithSwing.addLabel(p1, gbc, "World", 0, 1);
p1.setVisible(true);
//creates a second JPanel that also uses a grid layout
JPanel p2 = new JPanel(new GridBagLayout());
//adds the panel at the top of window2
window2.add(p2, BorderLayout.NORTH);
//sets the panel visible so it can correctly display the labels, textfields, and buttons
p2.setVisible(false);
//uses the method created below to add JLabels to p2
MessingWithSwing.addLabel(p2, gbc, "Please Enter The Following", 0, 0);
MessingWithSwing.addLabel(p2, gbc, "Name: ", 0, 1);
MessingWithSwing.addLabel(p2, gbc, "Age: ", 0, 2);
//uses the method created below to add JTextFields to p2
MessingWithSwing.addTextField(p2, gbc, "", 1, 1, 6);
MessingWithSwing.addTextField(p2, gbc, "<age>", 1, 2, 6);
//uses the method created below to add a JButton to p2
MessingWithSwing.addButton(p2, gbc, "Enter", 0, 3);
p2.setVisible(true);
/* Issue:
* The someting like the line below would not work
* How would you access the text inputted into each JTextField?
*/
// String str = tempTF.getText();
} //end of Main Method
//first constructor makes a window that is completely resizable
public MessingWithSwing(String title, int sizeX, int sizeY) {
super(title);
setSize(sizeX, sizeY);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
//second constructor makes a window that is resizable but has minimum dimensions
public MessingWithSwing(String title, int sizeX, int sizeY, int minSizeX, int minSizeY) {
super(title);
setSize(sizeX, sizeY);
setMinimumSize(new Dimension(minSizeX, minSizeY));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
//This method adds a JLabel with an indicated text, at an indicated GridBagConstraints location, to an indicated JPanel
public static void addLabel(JPanel p, GridBagConstraints gbc, String str, int x, int y) {
gbc.gridx = x;
gbc.gridy = y;
JLabel tempLabel = new JLabel(str);
p.add(tempLabel, gbc);
}
//This method adds a JTextField with an indicated length and text, at an indicated GridBagConstraints location, to an indicated JPanel
public static void addTextField (JPanel p, GridBagConstraints gbc, String str, int x, int y, int len) {
gbc.gridx = x;
gbc.gridy = y;
JTextField tempTF = new JTextField(str, len);
p.add(tempTF, gbc);
}
//This method adds a JButton with an indicated text, at an indicated GridBagConstraints location, to an indicated JPanel
public static void addButton (JPanel p, GridBagConstraints gbc, String str, int x, int y) {
gbc.gridx = x;
gbc.gridy = y;
JButton tempB = new JButton(str);
p.add(tempB, gbc);
}
}
So if I understand Kequiang Li correctly it would look something like:
public static JTextField addTextField (JPanel p, GridBagConstraints gbc, String str, int x, int y, int len) {
gbc.gridx = x;
gbc.gridy = y;
JTextField tempTF = new JTextField(str, len);
p.add(tempTF, gbc);
return tempTF;
}
Then:
ArrayList<JTextField> tfList = new ArrayList<JTextField>();
tfList.add(ClassName.addTextField(p1,gbc,text,0,0,8));
String str = tfList.get(0).getText();
How to get the text inside your text fields totally depends on where and when you want to get the text.
Let's say you want to retrieve the text whenever you want, then you can make your addTextField returns the text field it has added. This way, you can keep track of all the text fields in a list, an array, or even a map, and just call getText on these text fields.
In another situation, you might want the text only when user presses the enter key in the text field, then you can bind listener to the text field. When the event occurs, you can have access to the source of the event, which is the text field and then retrieve the text.
I am working on a small example using Java Swing where I want to draw a sine graph on one panel and the co-ordinates of the graph in another panel. So I created a class that extends the JFrame then I created the JPanel for graph and co-ordinates. For displaying co-ordinates I am using JList. Now the problem is the co-ordinates are showing duplicate values. Here is my code:
public class MyFrame extends JFrame {
JList list;
DecimalFormat df = new DecimalFormat("#.###");
DefaultListModel model = new DefaultListModel();
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MyFrame frame = new MyFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MyFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 600, 600);
contentPane = new JPanel();
contentPane.setBorder(new LineBorder(new Color(0, 0, 0)));
setContentPane(contentPane);
contentPane.setLayout(new GridLayout(1, 2, 0, 0));
JPanel panel = new MyGraph();
panel.setBorder(new LineBorder(new Color(0, 0, 0)));
contentPane.add(panel);
list = new JList(model);
list.setVisibleRowCount(4);
JPanel panel_1 = new JPanel();
panel_1.setBorder(new LineBorder(new Color(0, 0, 0)));
panel_1.setLayout(new BoxLayout(panel_1, BoxLayout.Y_AXIS));
JLabel lblNewLabel_1 = new JLabel("X - Y");
panel_1.add(lblNewLabel_1);
JScrollPane slistScroller = new JScrollPane(list);
panel_1.add(slistScroller);
contentPane.add(panel_1);
}
class MyGraph extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
int xBase = 10;
int top = 100;
int yScale = 10;
int xAxis = 360;
int yBase = top + yScale;
g.drawLine(xBase, top, xBase, top + 2 * yScale);
g.drawLine(xBase, yBase, xBase + xAxis, yBase);
g.setColor(Color.red);
int x2=0, y2=0;
int x1 = xBase + 0;
int y1 = yBase - (int) (10*Math.sin(0) * yScale);
int i;
for (i = 0; i < 10; i++) {
x2 = xBase + i;
y2 = yBase - (int) (10*Math.sin(i) * yScale);
g.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
df = new DecimalFormat("#.###");
model.addElement(i +" -- " + df.format(10*Math.sin(i)));
}
model.addElement("------END----------");
}
}
}
Here is the output of my program:
As per my program, I have a for loop from angles 0 to 10 and I am adding the values to DefaultListModel model which is added to JList list.
Can someone please help me where I am doing mistake in this code?
Also even when I have this line list.setVisibleRowCount(4); , I was expecting only 4 records displayed to the user with a scroll-bar, but as per the output image it is not working like that.
paintComponent may be any number of times, for any number of reasons, try resizing the frame and see what happens.
Your paint method should focus on doing just that, painting.
You need to change the process so that the paintComponent becomes depend on the model, not the other way round.
Take a look at Painting in AWT and Swing for more details about painting in Swing.
You may also want to consider using a ListCellRender to render the data in the model in the JList, this way, you could more easily share the model and it's data.
See Writing a Custom Cell Renderer for more details
This question already has answers here:
Resizing issue with canvas within jscrollpane within jsplitpane
(3 answers)
Closed 8 years ago.
The program i want to make is
Divide an applet/frame(awt) into two parts using panel. The first panel contains four buttons naming ellipse, rectangle, circle and triangle. Taking one button and asking coordinates and make a figure on the other panel.
Please someone explain me the concept or working because im not good at layouts and know methods to use to convey from one panel to other..
Thank you very much
I would recommend starting out with a layout manager.. if you want 2 JPanels next to each other, you can use the GridLayout layout manager. It takes 2 arguments, and one of it's overloaded constructors takes 4 arguments.
setLayout(new GridLayout(rows, columns)); //one commonly used constructor
setLayout(new GridLayout(rows, columns, horizontalSpacePixels, verticleSpace));
GridLayout, when used will reshape to fit the largest component, and make each part of the grid an equal size-- however this isn't the case when you use a GridLayout inside of a GridLayout (the inner GridLayout might be too big to fit within the confines that the outer GridLayout puts on it.). If I simply do
JFrame jf = new JFrame("Laying the grid out");
jf.setLayout(new GridLayout(5, 5));
JPanel[] jp = new JPanel[25];
JLabel[] jl = new JLabel[25];
for(int i = 0; i < 25; i++) {
jp[i] = new JPanel();
jp[i].setBackground(Color.YELLOW);
jl[i] = new JLabel("This is label no. " + (i+1));
jp[i].add(jl[i]);
}
//now to add all 25 components in the 5x5 grid; you simply add them, and it
//automatically positions the jpanels in the order that you place them.. left to right.
for(int i = 0; i < 25; i++)
jf.add(jp[i]);
Here is an example program that involves a simple GridLayout, and an actionListener that responds to button events by changing one of the JPanel's color.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Gui {
private JPanel p2;
private JLabel side2;
private JFrame jf;
public static void main(String[] args){
new Gui();
}
public Gui(){
jf = new JFrame("Holds 2 panels side by side.");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLayout(new GridLayout(1, 2));
JPanel p1 = new JPanel();
p2 = new JPanel();
p1.setBackground(Color.BLACK);
p2.setBackground(Color.BLACK);
p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
JLabel[] space = new JLabel[20];
for(int i = 0; i < 20; i++)
space[i] = new JLabel(" ");
JButton jb1 = new JButton("Button 1");
JButton jb2 = new JButton("Button 2");
jb1.addActionListener(new BListen());
jb2.addActionListener(new BListen());
p1.add(space[0]);
p1.add(jb1);
p1.add(space[1]);
p1.add(jb2);
p1.add(space[2]);
jf.add(p1);
side2 = new JLabel("Change the color here with the buttons there.");
side2.setForeground(Color.GREEN);
p2.add(side2);
jf.add(p2);
jf.setSize(600, 200);
jf.setVisible(true);
}
private class BListen implements ActionListener {
public void actionPerformed(ActionEvent e) {
String buttonClicked = e.getActionCommand();
if(buttonClicked.equals("Button 1")) {
JOptionPane.showMessageDialog(null, "You pressed Button 1.");
p2.setBackground(Color.BLUE);
side2.setForeground(Color.MAGENTA);
jf.setVisible(true);
}
else if(buttonClicked.equals("Button 2")) {
JOptionPane.showMessageDialog(null, "You pressed Button 2.");
p2.setBackground(Color.ORANGE);
side2.setForeground(Color.DARK_GRAY);
jf.setVisible(true);
}
}
}
}
I wrote this on screen keyboard that should display a keyboard.
my problem is that i want the JButtons fit their size of the labels and not to set fix size for all of the JButtons.
for example the numbers on keyboard: "1,2,3...." should get small jbutton and the keys "backspace" "tab" etc... should be bigger (fit the size of their label)
this is the code I wrote:
package Q2;
import java.awt.*;
import javax.swing.*;
public class MainPanel extends JPanel{
private JButton[][] button;
private JPanel[] panel; //Array of panels for each buttons line
private JPanel parent;
private static final String[][] key = {
{"`","1","2","3","4","5","6","7","8","9","0","-","+","Backspace"},
{"Tab","Q","W","E","R","T","Y","U","I","O","P","[","]"},
{"Caps","A","S","D","F","G","H","J","K","L",";","'","\\","Enter"},
{"Shif","Z","X","C","V","B","N","M",",",".","?","/"},
{" ",",","<","v",">"}
};
//Constructor for main Panel
public MainPanel(){
super();
setLayout(new BorderLayout());
TextField textField= new TextField(20);
Font font1 = new Font("david", Font.BOLD, 22);
textField.setFont(font1);
add(textField,BorderLayout.CENTER);
//initialize the parent panel and array of 5 panels and the buttons array
parent = new JPanel();
parent.setLayout(new GridLayout(0,1));
panel = new JPanel[5];
button = new JButton[20][20];
for (int row = 0; row<key.length; row++){
panel[row] = new JPanel();
for (int column = 0; column<key[row].length; column++){
button[row][column] = new JButton(key[row][column]);
button[row][column].setPreferredSize(new Dimension(key[row][column].length()+80,30));
button[row][column].putClientProperty("row", row);
button[row][column].putClientProperty("column", column);
button[row][column].putClientProperty("key", key[row][column]);
//button[row][column].addActionListener(new MyActionListener());
panel[row].add(button[row][column]);
}
parent.add(panel[row]);
}
add(parent,BorderLayout.SOUTH);
}
/*
//panel for line 1 of keyboard buttons - numbers
protected JComponent getPanelLine1(){
JPanel panel1 = new JPanel();
for (int i=0; i<10; i++){
}
}
//panel for line 1 of keyboard buttons - Q-P
protected JComponent getPanelLine2(){
}
//panel for line 1 of keyboard buttons - A-L
protected JComponent getPanelLine3(){
}![enter image description here][1]
//panel for line 1 of keyboard buttons - Z-M
protected JComponent getPanelLine4(){
}
//panel for line 1 of keyboard buttons - space and arrows
protected JComponent getPanelLine5(){
}*/
}
image:
As discussed here, don't set the preferred size!
// button[row][column].setPreferredSize(new Dimension(key[row][column].length()+80,30));
Instead set the margins
button[row][column].setMargin(new Insets(10, 20, 10, 20));
// Insets ( top, left, bottom, right )
And/or set the font size
Font font = button[row][column].getFont();
String family = font.getFamily();
int style = font.getStyle();
button[row][column].setFont(new Font(family, style, 24));
You probably don't want to create a new font every iteration, but it's just showing you how to get the defaults from the button
Doing either of these things will increase the preferred size of the panel accordingly, taking into account the size of the text contained within it