Can I get OwnerDrawLabelProvider to draw outside of the cell? - java

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.

Related

How make drawing restrictions in own gui window?

I want make gui window, but i don't know how to restrict drawing. What i mean? When you scrolling window, some ui elements drawing, and some "being cut off". See in image this restrict? I need that: (IMAGE)
I find glScissor, but i don't know how to used it
glScissor could work for exactly this purpose (scrolling).
It uses a per-fragment 'scissor test' to check whether a fragment is in the boundaries of the scissor box specified by glScissor. Nothing can be modified outside of the box, so this is a way to restrict drawing and rendering.
It takes in the position of the bottom left of the box as the first two parameters, and the last two are the width and height respectively. (You may have to call glEnable(GL_SCISSOR_TEST) first, as the scissor test is usually disabled.)
In this case, you can set the scissor box to the dimensions of the GUI window, so that you can cut off individual pixels of the GUI when the user scrolls.

How to avoid Swing combining repaint() requests?

Swing normally combines multiple repaint() requests, in order to drive the paintComponent() method only once and thus enhance performance. Normally, this is what you want.
In my application, however, this is undesirable. My component is a large screen full of text (like a text editor). Each character includes attributes like foreground/background color and styles (like BOLD). Repainting the entire screen (which repaint(() does by default) is an expensive operation, and introduces unnecessary latency, when only updating a few disparate characters on-screen.
Therefore, I call repaint(x, y, width, height) multiple times, but only for those areas that have actually changed (typically, 50 characters or less, which may be scattered about the screen in two or three separate, contiguous areas).
The problem is, typically I will have characters change at the top and bottom of the screen. I call repaint for each of the affected areas, but Swing combines my multiple repaint(...) requests into a single repaint(...) request (this is default behavior) by computing the union of the areas to be repainted. This results in a single call to paintComponent() but with a large clipping rectangle (as returned by getClipBounds()) which encompasses all areas to be updated. Thus, I wind up repainting a large area of the screen, anyway (based on the ClipBounds), which is counter-productive and what I wish to avoid, since only a small portion of the screen has actually been modified and therefore needs to be repainted.
Question: Is there any way to mitigate this behavior, so that my paintComponent() method repaints only those areas that have been modified, and avoids unnecessary repainting of unmodified areas?
Additional detail, as requested:
The class is derived from JComponent. Basically, it's just an "empty" window on which I draw text characters using Swing's API. The window's maximum size is about 83 rows by 320 columns per row (this is on an Apple Cinema display), so for an 8x16 font, that's 2560x1328.
Basically, the application is a text editor (think: vi). The bottom line of the display is a Status Line. In a worst-case scenario, i might move the cursor one position to the right at the top of the window. This would cause the Status Line at the bottom of the window to be updated to reflect the new cursor position (row, column). So, we have a few locations changing at the top of the window, and a few locations changing at the bottom of the window. I would issue 2 repaint(...) requests, one for each modified area of the window. However, repaint() will combine those two requests, and call paintComponent() once with a bounding rectangle (which defines the area to be repainted) that is the union of the two areas that were actually updated. The resultant rectangle will be very large, extending from the top of the window to the bottom. Thus, in paintComponent(), I wind up repainting a large part of the screen, even thought the vast majority of it was not modified. That is what I'm trying to avoid.
Is there any way to mitigate this behavior, so that my paintComponent() method repaints only those areas that have been modified,
You could try using the paintImmediately(...) method of the JComponent class.
This will result in multiple smaller paint requests being done right away without the benefit of the RepaintManager. Only you can decide is multiple smaller requests performs better than a single larger paint request.

Java Picture Color Area Distinguishing

I have this picture and I wish to be able to read each individual picture, load it up into a paint method and add Mouse Listeners to each spot of color but not any of the black background. I do not wish to include ANY of the black background as a "button" and only have the colored spots have mouselisteners of their own so I can distinguish which color spot I have pressed. Does anyone have any ideas? Thanks!
I suppose you could approach it this way:
List<Shape> buttons = ...
for each pixel in the picture, top left to bottom right {
if the pixel is not black {
if the pixel is not already contained in one of the buttons {
iterate over every pixel towards the right until you reach a different color
iterate over every pixel towards the bottom until you reach a different color
// now you have the bounds of your button
// create a new Rectangle and add it to your list.
}
}
}
I've never attempted something like this, nor have I tested the above method, but to me it seems like it should work.
Why can't you just duplicate the picture with JButtons and JPanels and simplify your life?
The mouseListener returns a location, so I would use that location to inspect the image at the corresponding pixel, then branch to do the required action. If the pixel turns out to be black, you simple do nothing.
The image can be inspected via a BufferedImage object and a Raster.
Alternatively, one could inspect the image via BufferedImage and a Raster, and create corresponding Objects for each color square located, printing and handling each one separately.

How to delete lines that are drawn in GUI?

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.

Painting Program

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.

Categories

Resources