I have Java applet to draw an array (just some rectangle one after another).
When user select to create array of size n, it will draw n rectangles connected together. When n gets bigger, the graphics get bigger, but since i use JPanel to draw the array, and JPanel won't scroll, i have to add that JPanel into a JScrollPane, but still it won't scroll. The user can see only part of the whole array.
Anyone can give me some help?
Here is my code:
public class ArrayPanel extends JPanel {
....
public void paintComponent(Graphics g) {
...draw array here..
// I wish to get the updated size of the graphis here,
// then i can reset the preferredSize()....?
System.out.println("width=" + getWidth() + " height=" + getHeight());
}
}
public class ArrayDemo extends JPanel {
public ArrayDemo() {
super(new BorderLayout());
arrayPanel = new ArrayPanel();
arrayPanel.setPreferredSize(new Dimension(400, 300));
JScrollPane container = new JScrollPane(arrayPanel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
container.setPreferredSize(arrayPanel.getPreferredSize());
add(container, BorderLayout.CENTER);
...
}
}
Don't set the size in paintComponent.
You did not provide that code, but you have some position in your code where you know the size of that array, and the size of your rectangles, so set dimensions of your JPanel there.
Here is an example (using JFrame, not Applet, but the ideas is the same) that looks like this:
alt text http://img186.imageshack.us/img186/143/so2305419.png
public class ScrollPanelFrame extends JFrame{
public ScrollPanelFrame() {
ArrayPanel panel = new ArrayPanel(20, 20);
JScrollPane container = new JScrollPane(
panel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
getContentPane().add(container);
}
class ArrayPanel extends JPanel {
final int RECTANGLE_WIDTH = 100;
final int RECTANGLE_HEIGHT = 100;
int rectangleCountX;
int rectangleCountY;
public ArrayPanel(int rectangleCountX, int rectangleCountY) {
this.rectangleCountX = rectangleCountX;
this.rectangleCountY = rectangleCountY;
this.setPreferredSize(new Dimension(RECTANGLE_WIDTH * rectangleCountX,
RECTANGLE_HEIGHT * rectangleCountY));
}
#Override
public void paintComponent(Graphics g) {
for(int x = 0 ; x < rectangleCountX ; x++) {
for(int y = 0 ; y < rectangleCountY ; y++) {
g.setColor(new Color(0, 0, (x+y)*64 % 256));
g.fillRect(x*RECTANGLE_WIDTH, y*RECTANGLE_HEIGHT,
RECTANGLE_WIDTH, RECTANGLE_HEIGHT);
}
}
}
}
public static void main(String[] args) {
ScrollPanelFrame frame = new ScrollPanelFrame();
frame.setSize(600, 400);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
Related
As the title says, I'm having a hard time trying to draw some rectangles (filled) in JApplet.
The exact goal is to have a 50x50 table and when you click on a targeted cell, to make it filled (possibly done by drawing a filled rectangle). I have done the maths about the coordinates of the starting point, but for some reason I can't draw the new rectangle in the MouseClicked method. Any suggestions?
public class Main extends JApplet {
public static final int DIMX = 800;
public static final int DIMY = 800;
public static final int ratio = 16;
Graphics g;
boolean drawing;
public int cX;
public int cY;
public Main() {
JPanel MainFrame = new JPanel();
MainFrame.setPreferredSize(new Dimension(400, 800));
MainFrame.setBackground(Color.LIGHT_GRAY);
JPanel Table = new JPanel();
Table.setPreferredSize(new Dimension(800, 800));
Table.setBackground(Color.LIGHT_GRAY);
add(MainFrame, BorderLayout.EAST);
add(Table, BorderLayout.WEST);
addMouseListener(new clicked());
}
public void paint(Graphics g) {
super.paintComponents(g);
g.setColor(Color.black);
for (int i = 0; i <= 800; i += 16) {
g.drawLine(0, i, 800, i);
g.drawLine(i, 0, i, 800);
// g.fillRect(cX, cY, 16, 16);
}
}
public static void main(String[] args) {
JFrame win = new JFrame("Retarded Bullshit");
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.setPreferredSize(new Dimension(1216, 840));
win.setContentPane(new Main());
win.pack();
win.setVisible(true);
}
public class clicked extends JApplet implements MouseListener {
public int cX;
public int cY;
Graphics g;
#Override
public void mouseClicked(MouseEvent e) {
// Point a = e.getLocationOnScreen();
int cellX = e.getX();
int cellY = e.getY();
if (cellX < 800 && cellX > 0 && cellY < 800 && cellY > 0) {
cX = cellX / 16 + 1;
cY = cellY / 16 + 1;
JOptionPane.showMessageDialog(null, "" + cX + " " + cY);
}
This is a relatively simple concept (no offense).
To start with, don't mix your code with JApplet and JFrame. If you want to use your application in these two mediums, separate the logic into a separate component (like JPanel) which you can easily add to either. You really shouldn't add a top level container to another top level container (adding an applet to a frame) - it's messy.
Avoid overriding the paint methods of top level containers (like JApplet), instead, use a custom component (like JPanel) instead and override it's paintComponent method.
In your example, you should be calling super.paint rather then super.paintComponents. paint does important work, you don't want to skip it - but you should be using JComponent#paintComponent
MouseListeners should added to the components that you are interested in managing mouse events. Because clicked is never added to any containers, it will never recieve mouse events.
Take a look at
How to write mouse listeners
Performing Custom Painting
2D Graphics
Painting in AWT and Swing (because every Swing developer should have an understanding of this)
public class SimplePaint03 {
public static void main(String[] args) {
new SimplePaint03();
}
public SimplePaint03() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PaintPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPane extends JPanel {
private List<Shape> grid;
private List<Shape> fill;
public PaintPane() {
grid = new ArrayList<>(5);
fill = new ArrayList<>(5);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
for (Shape shape : grid) {
if (shape.contains(e.getPoint())) {
if (fill.contains(shape)) {
fill.remove(shape);
} else {
fill.add(shape);
}
}
}
repaint();
}
});
int colWidth = 200 / 50;
int rowHeight = 200 / 50;
for (int row = 0; row < 50; row++) {
for (int col = 0; col < 50; col++) {
grid.add(new Rectangle(colWidth * col, rowHeight * row, colWidth, rowHeight));
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
for (Shape cell : fill) {
g2d.fill(cell);
}
g2d.setColor(Color.BLACK);
for (Shape cell : grid) {
g2d.draw(cell);
}
}
}
}
Additional
Information from one paint cycle to another is not maintained. You are required to repaint the component exactly the way you want it to appear. This means you will need to maintain a list of click points that can be repainted at any time.
Start by reading the Swing tutorial on Custom Painting.
Custom painting is done by overriding the paintComponent() method of a JPanel or JComponent(). Then you add the panel to the JApplet.
If you only want to paint certain squares then you are going to need a List to keep track of which cells to paint. Then every time you repaint the component you will need to loop through the List and paint the cells.
Your MouseListener would not extend JApplet. When you click on a cell you would update the List from above to indicate that the cell needs to be painted. Then you would invoke repaint() on the panel so that your painting code will be invoked.
You may also want to look at Custom Painting Approaches which gives two different ways to do this type of painting depending on your exact requirement.
I have a class , called boardGUI , it has a list of 64 labels (like a chess board). Every label coresponds to a specific tile on the board.
List<JLabel> labelList = new ArrayList<>();
In another class, I'm trying to set some of this labels opaque, with setOpaque(true) method , whenever I click on one of the labels (inside mouseClicked method).
JLabel l1 = boardGUI.labelList.get(1);
l1.setOpaque(true);
The problem is that although l1 refers the right label in labelList (I checked with the debugger) , it doesn`t make any visual change (on the GUI ).
But, if I'm trying to set opacity of the labels in the boardGUI class , it's working.
for (int i=0;i<64;i++)
labelList.get(i).setOpaque(true);
Where can the problem be?
here is the class where I'm trying to apply the changes :
public class Controller {
private Board board = new Board();
private BoardGUI boardGUI = new BoardGUI();
public Controller () {
boardGUI.setVisible(true);
boardGUI.addLabelListener(new LabelListener());
}
class LabelListener implements MouseListener{
#Override
public void mouseClicked(MouseEvent arg0) {
JLabel l1 = boardGUI.labelList.get(1);
l1.setOpaque(true);
}
BoardGUI class (there's more code , but it's not relevant) :
public class BoardGUI extends JFrame{
List<JLabel> labelList = new ArrayList<>();
public BoardGUI() {
createView();
}
public void createView() {
createLabels(mainPanel);
}
public void createLabels(JPanel mainPanel) {
int startX = 100;
int startY = 87;
int x = 100;
int y = 87;
int j = 0;
for (int i=0;i<64;i++) {
JLabel label = new JLabel();
label.setBounds(x , y , 62, 62);
labelList.add(label);
mainPanel.add(label);
if ( (i == 7*(j+1) +j )) {
x = startX;
y = startY + 62 *( i / 7);
j=j+1;
}
else {
x = x+62;
}
}
}
You need to set both background color and opaqueness; here's an example to show how these play together:
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.getContentPane().setBackground(Color.GREEN);
JLabel label1 = new JLabel("label1");
label1.setBackground(Color.RED);
label1.setOpaque(false);
frame.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
label1.setOpaque(!label1.isOpaque());
label1.setBackground(label1.getBackground() == Color.RED ? Color.BLUE : Color.RED);
}
public void mouseReleased(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
});
frame.add(label1);
frame.pack();
frame.setVisible(true);
}
The label is initially transparanet, then changes to BLUE and opaque and back with every MouseClick. So basically, you would need to set the background color together with opaque (the RED color is just to demonstrate that it is never shown as the label is never both opaque and RED).
I don't understand why i have to set Component.setPreferredSize() to draw and why my ovals are not placed in one place. Also i got some other questions, which are described below.
public class PaintPanel extends JPanel implements ActionListener
{
private void initStructure()
{
for (int i : new Range(MAX_AGENTS)) {
Agent agent = new Agent();
agents.add(agent);
add(agent);
}
}
//i want to override parent class 'add', to easy call 'actionPerformed' on children elements.
public Component add(Element comp)
{
elements.add(comp);
return super.add(comp);
}
#Override
public void actionPerformed(ActionEvent e)
{
for(Element element: elements){
element.actionPerformed(e);
}
repaint();
}
//ELEMENT is abstract class: 'public class Element extends JComponent implements ActionListener'
public class Agent extends Element
{
public Agent()
{
super();
// setPreferredSize(new Dimension(120,120)); !!!! a-a, i don't know the future size of the oval or triangle, i don't want and i can't set this :(
setVisible(true);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
System.out.println("draw"); //called
Point p1 = new Point(1, 1);
Point p2 = new Point(101, 101);
Point p3 = new Point(10, 10);
int[] xs = { p1.x, p2.x, p3.x };
int[] ys = { p1.y, p2.y, p3.y };
Polygon triangle = new Polygon(xs, ys, xs.length);
g.setColor(new Color(255,255,255)); // !! never painted
g.fillPolygon(triangle); //!! never painted
g.drawOval(10,10,10,10); // !!!! painted only when i set preferredSize
}
#Override
public void actionPerformed(ActionEvent e)
{
System.out.println("i am alive"); //working
}
}
In case, if i set preferred size i got the picture below.
So.
Question
1) Is there any patterns to not set preferred size and draw component inside Component calling paint() on contentPanel?
2) Why g.fillPolygon not working?
3) Why my ovals are not placed in one point?
Why my ovals are not placed in one point?
I would guess you are adding your Agent components to a JPanel. By default a JPanel uses a FlowLayout. So each component is placed 120 pixels apart and flow to a new line when the row is filled.
i don't know the future size of the oval or triangle, i don't want and i can't set this
Don't use the drawOval(...) method. Instead use a Shape object that represents an oval. Then you can get the size of the Shape and use this value in the getPreferredSize() method mentioned by #hovercraft.
Check out Playing With Shapes for more info on this concept. Of course if you use this concept you would need to define the Shapes as instance variable so the Shape can be referenced by both the paintComponent() and getpreferredSize() methods.
The issue is if the JPanel doesn't have a preferred size, and if it is being added to a container that uses a layout manager that doesn't fill the container (such as FlowLayout), then how will the GUI know what size the drawing JPanel should be? I've heard that better than calling setPreferredSize(...) on your JPanel is to override its Dimension getPreferredSize() method (ask kleopatra, a Swing expert on this site).
Regarding:
Why g.fillShape not working?
Check the API -- does Graphics have a fillShape method? Nope. But Graphics2D has a fill(Shape s) method, and that's what you want.
Why my ovals are not placed in one point?
Please clarify this and provide details. What do you mean by "placed in one point"? What behavior exactly are you expecting and why?
Edit: your triangle is not being drawn because all the points are co-linear!
For example:
import java.awt.*;
import javax.swing.*;
public class MyDrawingPanel extends JPanel {
private static final int PREF_W = 100;
private static final int PREF_H = PREF_W;
// private Point p1 = new Point(1, 1);
private Point p1 = new Point(30, 1);
private Point p2 = new Point(100, 101);
// private Point p3 = new Point(10, 10);
private Point p3 = new Point(50, 10);
private int[] xs = { p1.x, p2.x, p3.x };
private int[] ys = { p1.y, p2.y, p3.y };
private Polygon triangle = new Polygon(xs, ys, xs.length);
public MyDrawingPanel() {
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(new Color(255, 255, 255)); // !! never painted
g.fillPolygon(triangle); // !! never painted
g.drawOval(10, 10, 10, 10); // !!!! painted only when i set preferredSize
}
private static void createAndShowGui() {
int rows = 4;
int cols = 4;
JPanel gridPanel = new JPanel(new GridLayout(rows, cols));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
gridPanel.add(new MyDrawingPanel());
}
}
JFrame frame = new JFrame("PaintPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gridPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I need help with drawing the grids to the GUI as well as the program later letting me change the colour of the boxes drawn. I know i will have to use paintComponent(Graphics g), but i have no idea how or where.
So here is a copy of the code i have got so far ( even though i have been told it can be quite daunting just being given code i think it is the best way for people to help and not just do it for me). From the top it sets values, creates the GUI, calls the GUI, fills a 2d array with boxes( i think). Then in the Boxes class setting values the boxes class will need, then the start of how to draw them (didn't know how to work it out), then some seta methods for the x and y coordinates.
what i would like you to do is show how to have the boxes be drawn to the Jpanel, to make a grid and then to show me how to change the colour to different shades of blue, depending on a external value.
import java.awt.*;
import java.awt.Graphics;
import java.util.*;
import javax.swing.*;
public class NewGrid {
Boxes[][] Boxs;
int BoxesX;
int BoxesY;
NewGrid() {
buildtheGUI();
}
JFrame frame = new JFrame();
JPanel panel = new JPanel();
public void buildtheGUI() {
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
new NewGrid();
}
public void addboxes() {
Boxs = new Boxes[panel.getWidth() / 10][panel.getHeight() / 10];
for (int i = 0; i < panel.getWidth() / 10; i++) {
for (int j = 0; j < panel.getHeight() / 10; j++) {
Boxs[i][j] = new Boxes();
Boxs[i][j].setx(i * (panel.getWidth() / 10));
Boxs[i][j].sety(j * (panel.getHeight() / 10));
Boxs[i][j].draw(null);
}
}
}
}
public class Boxes extends JPanel {
int x;
int y;
int width = 10;
int hieight = 10;
Color colour = Color.BLACK;
public void draw(Graphics g) {
g.setColor(colour);
g.fillRect(x, y, width, hieight);
}
public void setx(int i ){
x = i;
}
public void sety(int i ){
y = i;
}
}
I can't comment something, to try to make things easier,
I code there box.putClientProperty(unique_identifier, value_for_identifier), you can to multiple this method as you want
from every Swing Listener you can to get this and proper coordinated defined in putClientProperty
.
JComponent comp = event.getComponent();
String strRow = (String) comp.getClientProperty("row");
String strColumn = (String) comp.getClientProperty("column");
simple code
import java.awt.*;
import java.awt.Graphics;
import java.util.*;
import javax.swing.*;
public class NewGrid {
private int row = 10;
private int column = 10;
private JFrame frame = new JFrame();
private JPanel panel = new JPanel();
private NewGrid() {
addboxes();
panel.setLayout(new GridLayout(row, column));
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private void addboxes() {
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
Boxes box = new Boxes();
box.putClientProperty("row", row);
box.putClientProperty("column", column);
panel.add(box);
}
}
}
public static void main(String[] args) {
Runnable doRun = new Runnable() {
#Override
public void run() {
new NewGrid();
}
};
SwingUtilities.invokeLater(doRun);
}
}
class Boxes extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(20, 20);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(20, 20);
}
#Override
public void paintComponent(Graphics g) {
int margin = 2;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2,
dim.height - margin * 2);
}
}
I have a JTextArea and it's riding on top of a JScrollPane. Anyways, I know I can use the getViewPort() method to set the opaque property of the viewport, but I cannot seem to find any sign of how to do that anywhere.
Here is what I have so far:
if (e.getKeyCode() == KeyEvent.VK_F)
{
if (sp.isVisible())
{
sp.setVisible(false);
}
else
{
sp.setVisible(true);
}
}
You need to use setOpaque(false) to make it transparent. Call that both on the JScrollPane, and on it's ViewPort.
sp.setOpaque(false);
sp.getViewport().setOpaque(false);
You'll also have to call setOpaque(false) on the JTextArea, if you want that transparent as well.
Your colloquy with #Serplat suggests that you may be confounding opacity and transparency.
Opacity is a boolean property of Swing components used to optimize drawing:
true: The component agrees to paint all of the bits contained within its rectangular bounds.
false: The component makes no guarantees about painting all the bits within its rectangular bounds.
Transparency is a means of compositing digital images, as seen in this example.
Considering the distinction may help to clarify your question or focus your search for more information.
Addendum: Based on #camickr's example, the example below shows a blue square that "sticks" to the viewport, while the gray checkerboard may be scrolled over it.
import java.awt.*;
import javax.swing.*;
/** #see https://stackoverflow.com/questions/2846497 */
public class ScrollPanePaint extends JFrame {
private static final int TILE = 64;
public ScrollPanePaint() {
JViewport viewport = new MyViewport();
viewport.setView(new MyPanel());
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewport(viewport);
this.add(scrollPane);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
private static class MyViewport extends JViewport {
public MyViewport() {
this.setOpaque(false);
this.setPreferredSize(new Dimension(6 * TILE, 6 * TILE));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.fillRect(TILE, TILE, 3 * TILE, 3 * TILE);
}
}
private static class MyPanel extends JPanel {
public MyPanel() {
this.setOpaque(false);
this.setPreferredSize(new Dimension(9 * TILE, 9 * TILE));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.lightGray);
int w = this.getWidth() / TILE + 1;
int h = this.getHeight() / TILE + 1;
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
if ((row + col) % 2 == 0) {
g.fillRect(col * TILE, row * TILE, TILE, TILE);
}
}
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ScrollPanePaint();
}
});
}
}
Code for JScrollpane Transparent Background.
JScrollPane scrollPane = new JScrollPane();
JViewport viewport = new JViewport();
//Component that need to be added in Scroll pane//
viewport.setView(new JPanel());
viewport.setOpaque(false);
scrollPane.setViewport(viewport);
scrollPane.getViewport().setOpaque(false);
scrollPane.setOpaque(false);
// Add Scrollpane to Jframe or JPanel//
add( scrollPane,BorderLayout.CENTER);