I've been doing a program that will paint lines in a JLabel with picture. after creating those lines, I want to delete those lines that I've drawn. For example, I want to delete the
d.drawLine(label.getGraphics(), 120,215,330,120);
Drawing does not work like that. Once you draw a line, it no longer exists as a line, just as a bunch of pixels that aren't functionally different from all the other pixels. There are however possible workarounds:
Redraw the line using the background colour (e.g. white). This only works if the line doesn't cover anything.
Make a Line class and keep a list of them. When you want to delete a line, remove it from the list, clear all lines, and then redraw all the lines in the list.
You can't delete anything on a GUI. All you can do is keep writing over the top of what's there. If you want to change a black line back to a white background, you can write a white line over the top.
I think you're confusing a canvas type implementation (Java) with a graphics DOM tree type implementation (SVG in browsers, for example).
In a DOM implementation you can remove the element and have the application work out what is the dirty region and to repaint any elements that have sections that fall within that dirty region (usually a rectangle).
In a canvas implementation like Java, you paint directly to a graphics object and once you've painted, the canvas doesn't know where you painted. Generally, you need to implement a mechanism to work out what is dirty and repaint your component in the affected areas. Such a mechanism is known a scene graph.
label.revalidate();
label.repaint();
...
public void paintComponent(Graphics g) { do not draw lines but the rest }
Drawing happens event based, so you put your drawing code into paintComponent or paint.
The redrawing can be triggered i.a. with a repaint.
Related
I have a Jface TableViewer in my Eclipse RCP app whose columns are all drawn by OwnerDrawLabelProviders. My cells are now all being drawn the way that I want, but I'm unable to use an OwnerDrawLabelProvider to draw anything outside of the current cell being drawn.
I've illustrated the problem below. If the cell with the green background is being drawn, and I attempt to draw a red line across the entire table, the red line stops being drawn as soon as I exit the cell.
I thought that what was happening here is that the other cells were drawing over the top of the red line, but I showed this wasn't the case by deactivating the paint(), measure(), and erase() methods for the next column. Instead, I think what's happening is that the Table is hiding my red line in a lower display layer as soon as it leaves the cell.
Is there any way to draw outside the cell with an OwnerDrawLabelProvider? I have a workaround, namely issuing the same draw command in each cell that would be drawn in, but that's pretty ugly and could potentially lead to performance problems.
The GC that is passed to the paint/measure/erase methods has the clipping area set to just the current cell. Any drawing operation you do on the GC that is outside of the clipping area is ignored.
You could try calling the GC.setClipping method to change the clipping area but you may still have problems with things being overwritten.
I have an seemingly very simple task at hand. I have a grid (500x500 right now) I want to visualize as it is populated and I want to write a class in Java that makes this easy for me to do. I'm thinking something along the line of:
public class Screen {
...
public void plot(x,y) {
// change the color of pixel x,y to black
}
public void clear() {
// fill the screen with white
}
}
I have been looking around and quickly found Canvas in awt, however from what I have been able to figure out so far, this widget will only allow me to draw on to it by overriding its paint method. This is far from optimal in my case as this will require me to draw the entire grid every time I wish to do just plot one single pixel.
Is there any way to get canvas to just draw a single pixel rather than the entire canvas? Or some other way to accomplish what I look for here?
I would prefer to avoid having to use any external libraries.
You will need to override the paint method to display the entire grid.
However, what you can do is create a BufferedImage that flips the one pixel, and draw that entire image to the component in the paint method, using Graphics.drawImage().
Unfortunately you have to override paint() and render the entire grid every time paint() is called. That's how graphical components work - the windows system/OS may request to repaint the component at any time (eg. when the window is re-shown/resized/moved)
I am hoping the saveLayer methods will allow me to do draw onto different "layers" and then once the drawing has finished, merge the layers with the canvas in whichever order i choose.
The obvious question is "why dont you just rearrange your drawing operations instead?" The answer is I can't:
I have a Path that I need to draw onto a Canvas. In the background/lowest z-index I want to draw the path closed and with a few additional points using a fill style. Then on top of that, I want to draw an outline of only the points that were originally in the Path.
Since I cannot undo the adding of points to the Path, my only choices are to clone the path, or to draw to a second layer which can later be placed on top of everything else.
saveLayer() seems to offer that functionality but it doesnt behave the way I was expecting. The basic flow of my operations is like this:
int overlay = canvas.saveLayer(...);
// drawing operations for my uppermost layer
...
int background = canvas.saveLayer(...);
// drawing operations for my background layer
...
// merge the offscreen background bitmap with the canvas:
canvas.restoreToCount(background);
// merge the offscreen overlay bitmap with the canvas:
canvas.restoreToCount(overlay);
When the code runs, the ordering of background and overlay have not changed at all; what gets drawn first is at the bottom and what gets drawn last is on top. Even stranger to me is that I can completely comment out both calls to restoreToCount() and nothing changes. According to the javadoc, nothing should be drawn to the canvas until a balancing restore() is invoked.
Obviously I am completely misunderstanding the function of this method. Can anybody help me to understand saveLayer's usage, or perhaps suggest an alternate way to layer my drawing operations?
Thx!
Nick
saveLayer() does not let you rearrange the layers in a random order. The only way to do it is to draw in offscreen bitmaps yourself. Note also that your view's parent will call save()/restore() around your onDraw() call, which will cause your layers to be composited.
I'm writing a simple painting program. To simulate a pencil drawing, I've stored the drawn points in a set, so when the window is resized the points won't be gone, and whenever another point is added I call the repaint method (the paint method draws all paints in the array on screen). But when the number of points increases, the program runs slowly.
Is there a more efficient method to do this?
The fastest way to get constant-speed repainting is to store the entire image that's drawn as a bitmap, and of course update it when the user draws. This way, you can redraw the right thing, and even add scrollbars and the like if you want. You can keep the array of points for an "undo" feature, for example.
If instead you want to make a vector-drawing program, then you have to keep the individual primitive operations (such as line, rectangles, etc). In that case it still pays off to keep an image for fast repainting, and now the trick becomes how to efficiently update that image when the user modifies the drawing (e.g. by resizing a rectangle). One way to do that is to tile the drawing area into lots of smaller ones, so you only need to recompute the underlying image for the parts that intersect with the object being modified by the user.
In both techniques, you'd use double-buffering just so that the user doesn't perceive flicker. But with double-buffering alone, the "redraw the whole set of points" would still be slow.
Since you haven't give any code, I am guessing that you are using primitive drawing methods (like draw a line or point).
A good option would be to use the Double Buffering technique to do the painting.
Look up GeneralPath.
What you can do is create a Shape class, that'll vary according to what you are going to draw (Rectangle, Triangle, Point, Line, etc.). You should do this even though now you're only drawing points.
When you create your Shape have code that checks what Shape to create, something like a switch/case statement:
...
case PENCIL:
if (generalPath == null) {
generalPath = new GeneralPath();
generalPath.moveTo(p1.x, p1.y);
} else {
generalPath.lineTo(p2.x, p2.y);
}
shape = generalPath;
break;
...
In the code that draws, simply call repaint and the Shape will be drawn.
I'm attempting to make a Java Applet that will allow me to draw a graph data structure in a canvas. I will do this by clicking where I want to create nodes, and clicking the nodes to connect them. The problem is I cannot get the paint() method to behave correctly. I add new nodes to the graph (and squares on the canvas) inside the mousePressed(MouseEvent e) method using,
Graphics g = this.getGraphics();
g.setColor(Color.blue);
g.fillRect(e.getX(), e.gety(), 40, 40);
Everything works fine, until I resize the window, and then all the filled rectangles vanish. I overrided the paint method to just an empty method, but the same thing still happens. I can't add the fillRect commands inside paint() because I don't know what rectangles exist until the user interacts with it using the mouse.
How can I use g.fillRect() inside the mouse listener methods and make them stick?
The problem is the place you're drawing to isn't persistant. At any moment, you can lose everything you've drawn to it. The paint(Graphics) method is called when this happens. You'll either need to repaint the entire picture every time this happens, or you'll need to set aside a canvas to draw to and copy the contents to your applet's Graphics as needed.
Here's how to create and draw to an image:
http://java.sun.com/docs/books/tutorial/2d/images/drawonimage.html
Then, in your paint method, use your Graphics' drawImage(...) method to display the image you've created.
I don't know if I'm reading this correctly, but why not just store the location of the last click in a variable to be painted later, when the paint() method is called?
You've got to override the window resize action listener and call repaint inside of it.
The Graphics is temporary. When a region gets dirty, it will be repainted.
The best way is to create a BufferedImage, paint to it on mousePressed and call repaint.
When paint is called, draw the Image onto the passed Graphics Object. This way you don't need to store the Rectangles and you got a buffer which will improve performance.