Java - Transparent JScrollPane - java

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);

Related

How to make a bunch of clickable panels in Java JFrame

I am trying to recreate the Game of Life in Java using JFrame. I have already completed most of the program but this one thing is bugging me. How do I make a bunch of fields(panels) which are clickable, so that the user can input their own pattern, instead of the computer randomly generating the pattern each time?
You could use a GridLayout layout manager to put all the JPanels in a grid, and for each JPanel, add an instance of the MouseAdapter class with addMouseListener() to listen for mouse clicks to flip their state. The instance of MouseAdapter would override mouseClicked() and within that function, flip the state of the JPanel.
This is just to make a complete example, but here would be the creation of the frame and setting its layout manager:
public static void main(String[] args) {
JFrame frame = new JFrame();
int width = 200, height = 200;
frame.setSize(width, height);
int rows = width/10, cols = height/10;
frame.setLayout(new GridLayout(rows, cols));
// add all the cells
for(int j = 0; j < cols; j++) {
for(int i = 0; i < rows; i++) {
frame.add(new Cell(i, j));
}
}
frame.setVisible(true);
}
Then for each cell, we have instances of this class:
class Cell extends JPanel {
int row, col;
public static final int STATE_DEAD = 0;
public static final int STATE_ALIVE = 1;
int state = STATE_DEAD;
public Cell(int row, int col) {
this.row = row;
this.col = col;
// MouseAdapter tells a component how it should react to mouse events
MouseAdapter mouseAdapter = new MouseAdapter() {
// using mouseReleased because moving the mouse slightly
// while clicking will register as a drag instead of a click
#Override
public void mouseReleased(MouseEvent e) {
flip();
repaint(); // redraw the JPanel to reflect new state
}
};
// assign that behavior to this JPanel for mouse button events
addMouseListener(mouseAdapter);
}
// Override this method to change drawing behavior to reflect state
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// fill the cell with black if it is dead
if(state == STATE_DEAD) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
public void flip() {
if(state == STATE_DEAD) {
state = STATE_ALIVE;
} else {
state = STATE_DEAD;
}
}
}
Alternatively, you could override the paintComponent() method of one JPanel, and do the above but use addMouseMotionListener() as well, that way your one panel can track which drawn grid cell the mouse is in, and you can control how they are drawn.

deleting previously clicked rectangle in java for thread [duplicate]

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.

JScrollPane doesn't update JScrollBar on JSplitPane

I want to create simple app able to edit images. Main view of app contains JSplitPane with two JScrollPane. Each JScrollPane contains JPanel. The right JPanel has several buttons etc. and the left JPanel is my drawing area.
Here is my problem...
When I first created JPanelDrawingArea I could set preferred size. If the size is bigger than size of JScrollPane the JScrollBars show up (in default it is equal). But when I load image to JPanelDrawingArea scroll bars don't update. Despite the fact I set new preferred size of JPanelDrawingArea (bigger than size of JScrollPane) scroll bars don't update unless I manually change the JSplitPanes divider position.
Here is my JSplitPane custom class:
public class DrawingPaneView extends JSplitPane{
private DrawingWorkMode drawingWorkMode;
private ImageWorkerView imageWorker;
JScrollPane workScrollPane;
JScrollPane pictureScrollPane;
private DrawingPaneController controller;
private Dimension minimumSize = new Dimension(100, 200);
private JPanel imagePanel;
public DrawingPaneView() {
setPreferredSize(new Dimension(ConfigClass.APP_WIDTH,ConfigClass.DRAWING_PANE_HEIGHT));
controller = new DrawingPaneController(this);
//Panel
drawingWorkMode = new DrawingWorkMode();
workScrollPane = new JScrollPane(drawingWorkMode);
//Image
imageWorker = new ImageWorkerView();
pictureScrollPane = new JScrollPane(imageWorker);
workScrollPane.setMinimumSize(minimumSize);
pictureScrollPane.setMinimumSize(minimumSize);
//addJPanels
this.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
this.setRightComponent(workScrollPane);
this.setLeftComponent(pictureScrollPane);
//addLeftPanelWithJButtonOnly
imagePanel = new ImagePanelView();
pictureScrollPane.setRowHeaderView(imagePanel);
this.setDividerLocation(ConfigClass.DRAWING_PANE_WIDTH);
this.setOneTouchExpandable(true);
}
//Change mode
public void changeMode(String mode){
drawingWorkMode.changeMode(mode);
}
}
And there is my custom JPanel which perform drawing:
public class ImageWorkerView extends JPanel {
private BufferedImage img;
private ImageWorkerController controller;
private int defaultBounds = 50;
private double scale=1.0;
int imgW;
int imgH;
public ImageWorkerView() {
//setLayout(new BorderLayout(0, 0));
controller = new ImageWorkerController(this);
}
public void setScale(double scale) {
this.scale = scale;
}
public void setImage(File image) {
try {
img = ImageIO.read(image);
if (img.getType() != BufferedImage.TYPE_INT_RGB) {
BufferedImage img2 =
new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics big = img2.getGraphics();
big.drawImage(img, 0, 0, null);
img = img2;
}
} catch (IOException e) {
System.out.println("Image could not be read");
}
}
private void adjustPreferredSize(Boolean defaultSize){
if(defaultSize){
//Calculate the proper size of drawing area
imgW = ConfigClass.DRAWING_PANE_WIDTH - ImagePanelView.PREFERRED_WIDTH-10;
imgH = ConfigClass.DRAWING_PANE_HEIGHT-50;
setPreferredSize(new Dimension(imgW,imgH));
controller.setWindowHeight(imgH);
}
else{
imgW = (int)(img.getWidth() * scale + (defaultBounds*2));
imgH = (int)(img.getHeight() * scale + (defaultBounds*2));
setPreferredSize(new Dimension(imgW,imgH));
controller.setWindowHeight(imgH);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if(img!=null){
if(scale!=1.0){
AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
AffineTransformOp aop =
new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC);
g2.drawImage(img, aop, defaultBounds, defaultBounds);
}
else
g2.drawImage(img, defaultBounds, defaultBounds, null);
adjustPreferredSize(false);
}
else{
adjustPreferredSize(true);
}
}
}
And how i load image:
public class ImageWorkerController {
ImageWorkerView view;
ImageModel model;
public ImageWorkerController(ImageWorkerView workerView) {
this.view = workerView;
this.model = ApplicationContext.getObject(ImageModel.class);
//Load image
ApplicationContext.getObject(Context.class).addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if(Context.IMAGE_LOADED.equals(evt.getPropertyName())){
view.setImage((File) evt.getNewValue());
view.repaint();
}
}
});
public void setWindowHeight(int h){
model.setDrawingWindowHeight(h);
}
}
As you can see there is adjustPreferredSize() method, when it is first called, and it sets preferredSize bigger than JScrollPane, JScrollBars appear. But when it is called again it does nothing.
What is interesting, when I manually change divider's location JScrollBars show up, on screen below you have an example:
http://s17.postimage.org/e1nkja3zx/liliebead.jpg
So there is some kind of event, which makes JScrollPane to update? I've tried several ways: updateUI(), repaint(), revalidate(). None of them worked.
Any ideas what I am doing wrong?
In short, you need to revalidate() your ImageWorkerView (right where you call repaint()). This will ask the component and its parent for "re-layout" and that in turn will trigger necessary adjustments for the scroll bars.
Thanks for your answer! Your suggestion made me think. What actually I did wrong is call revalidate() immediatelly after repaint() so in fact revalidate() executes before paintComponent method in ImageWorkerView (I found this out during debugging). The proper way to do this is:
ApplicationContext.getObject(Context.class).addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if(Context.IMAGE_LOADED.equals(evt.getPropertyName())){
view.setImage((File) evt.getNewValue());
//view.repaint();
view.paintImmediately(new Rectangle(1, 1));
view.revalidate();
}
}
});
So now paintComponent sets preferred size and then revalidate() adjust scroll bars.

allowing users to "draw" and resize JTextArea

I want to allow users to be able to "draw" with their mouse (click and drag) to create and size a JTextArea. As well, I would like to have the text areas as resizeable.
Something like this:
comes to mind, but as a JTextArea instead of just a square.
Is there something in Java that would allow me to easily do this? I first thought to allow the user to draw a rectangle and just grab the co-ordinates and size to create the JTextArea. I am unsure on how to do the resizing though.
Edit: "Component Resizer / Reszing" was the term I was looking for and I'm adding it here in case someone else is looking for something similar!
You can found a solution here
I have already try it and the result is very well. In the tutorial there is a reference to another implementation here.
The resizing the JTextArea can be done easily enough via calling setBounds(...) on it -- or better on the JScrollPane that holds it, but you will need to use a null or similar (JLayeredPane) layout on the container that holds the JTextArea and will likely need to repaint the container after resizing the JScrollPane. You will also have to revalidate the scrollpane's viewport so it will re-layout the textarea that it holds.
e.g.,
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class ResizeableTextArea extends JPanel {
private static final int PREF_WIDTH = 700;
private static final int PREF_HEIGHT = 500;
private static final int ROWS = 60;
private static final int COLS = 80;
private static final Color RECT_COLOR = new Color(180, 180, 255);
private JTextArea textArea = new JTextArea(ROWS, COLS);
private JScrollPane scrollPane = new JScrollPane(textArea);
private int x, y, width, height;
private boolean drawRect = false;
public ResizeableTextArea() {
setLayout(null);
add(scrollPane);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (drawRect) {
g.setColor(RECT_COLOR);
g.drawRect(x, y, width, height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_WIDTH, PREF_HEIGHT);
}
private class MyMouseAdapter extends MouseAdapter {
private int innerX, innerY;
#Override
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
innerX = x;
innerY = y;
width = 0;
height = 0;
drawRect = true;
}
#Override
public void mouseDragged(MouseEvent e) {
calcBounds(e);
drawRect = true;
ResizeableTextArea.this.repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
calcBounds(e);
drawRect = false;
scrollPane.setBounds(x, y, width, height);
scrollPane.getViewport().revalidate();
ResizeableTextArea.this.repaint();
}
private void calcBounds(MouseEvent e) {
width = Math.abs(innerX - e.getX());
height = Math.abs(innerY - e.getY());
x = Math.min(innerX, e.getX());
y = Math.min(innerY, e.getY());
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("ResizeableTextArea");
frame.getContentPane().add(new ResizeableTextArea());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
You should be able to use the Component Resizer.
that not really good idea, sure is possible to put Image or ImageIcon as BackGround, better would be use for that JLabel with Icon, then you can painting selection easily

How to change the size of the graphics

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);
}
}

Categories

Resources