I've got an application where I'd like for the user to be able to mouse-over and/or right click on a line that is being drawn on a JPanel. I fully expect that I'll implement the line as part of an object that will handle all of the behavior, but I've got a more fundamental question about how to implement the line shown in the below picture. First, the picture:
I can draw the line itself without any problem, but it's currently just being done in an overridden paintComponent() call in the parent JPanel. I have the rudiments of an idea on how to handle this:
public class ChassisLink extends JComponent implements MouseListener
{
//Rectangle to handle mouse-over and right-click for each segment?
public ChassisLink()
{
initializeLink();
}
private void initializeLink()
{
//Init stuff
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
//Paint the line(s)
}
//MouseListener events...
//When mouse-over on the line, display a tooltip
//When right clicking, display a different dialog
}
The issue I think I'm failing to understand is how to do the mouseover or click point check. Do I use a Rectangle and check whether the mouse is currently contained in that Rectangle, simply ignoring the triangular parts of the arrows? I'm perfectly sanguine about that. My issue then becomes how I would display these link objects over top of the existing JPanel that contains the chassis objects; it sounds like a candidate for a JLayeredPane, but any confirmation on that path?
Anyway, I appreciate any input people could give me. Feel free to ask for further explanation if something is a bit vague.
Thanks,
-Rich
You are on the right track. I would recommend using Area instead of Rectangle - you can get the arrows in that way too, and Area is extremely easy to manipulate using AffineTransforms.
Related
I am creating a java 2D game and have come to a point where I am thinking of creating "pop-up graphics" i.e graphics that will populate the screen when a certain event occurs. Say, you pick up a certain item, I want this item to be displayed in the middle of the screen in a box containing information about said item.
Currently I have one big paintComponent that paints all of the graphics for the game (tiles, entities, players etc (which has been done efficiently I might add)). I know that I can probably have a boolean value which checks if an item has been picked up in that method, but it feels wrong.
What I am wondering is, is there a way for items to have their own paintComponent so that when it is called, it will show say a bo for a brief period WITHOUT having a boolean value in the big paintComponent method that I currently use for everything?
Small code example (won't execute)
public class popUpGraphics extends (JComponent or JPanel or whatever works best for this scenario)
{
public popUpGraphics(){
}
#Override
protected void paintComponent(Graphics g){
//g.Draw(stuff);
}
}
and then somewhere in an event I instantiate this or somesuch.
I do not want this to override the other paintcomponent, I just want to add to it
(as if it was another layer) to the paintComponent
In short I want to know:
1. Is is possible to have brief graphics shown without including in the huge paintComponent method
2. What Swing library should be extended (JComponent, JPanel etc)
Thanks in advance!
I am making an app with javafx and I put Polygon shapes into a Pane and define the shapes (one for example below) as
shape.getPoints().addAll(new Double[] { ... points ... });
shape.setTranslateX(...);
shape.setTranslateY(...);
setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
System.out.println(hex.getResource().toString());
hex.pressed();
}
});
Then I add the shape to my pane
pane.getChildren().addAll(shape);
But when I click on the shapes, it seems like the click area is covering more than just the shape. It is covering up other click areas, so I am unable to click on some shapes, and I am accidentally clicking on others. But the shapes themselves are in the right position and look fine. They aren't physically covering each other up. Please let me know how I would fix the click area.
Also, I can't use the other layout classes since my shapes need to be put in a location explicitly, not just in a grid or next to each other.
What you're looking for is clipping.
Go ahead and add this to your code and that should resolve your issue.
pane.setClip(shape);
As for your second issue, I'm not sure what you're asking.
I've been working on a java game recently, and I have a lot of it figured out. One thing still plagues me, however. The way it's set up, a player moves across a background (the game board). Currently, every time the player moves, it repaints the whole frame, including the background. This causes a brief, yet annoying screen flicker whenever the player moves.
I've separated out my code to draw the background separately from the things that need to be repainted:
public void drawMap(Graphics pane) {...}
public void drawPlayer(Graphics pane) {...}
The problem is that I can't find a way to make the board stay on the screen when I use repaint(); , a necessity for the player to move. Any suggestions?
You should look into double buffering, basically you paint an image to the buffer, then paint the buffer. It should remove the flickering effect you are talking about. Below are a few helpful links:
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html
http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering
http://www.ecst.csuchico.edu/~amk/classes/csciOOP/double-buffering.html
Just comment if your having trouble understanding it.
UPDATE: I would also suggest you look in 'Killer game programming in java'. You can get a free ebook of one of the older versions. Some of it is a bit out dated, but the first few chapters about setting up a game loop and drawing to the screen etc are still very much relevant.
UPDATE 2: From the second link, try something like this:
private void drawStuff() {
BufferStrategy bf = this.getBufferStrategy();
Graphics g = null;
try {
g = bf.getDrawGraphics();
drawMap(g);
drawPlayer(g);
} finally {
// It is best to dispose() a Graphics object when done with it.
g.dispose();
}
// Shows the contents of the backbuffer on the screen.
bf.show();
//Tell the System to do the Drawing now, otherwise it can take a few extra ms until
//Drawing is done which looks very jerky
Toolkit.getDefaultToolkit().sync();
}
UPDATE 3: This post here gives a nice code sample that you can play with and adapt, that should give you the best idea on how to do double buffering
I suggest to avoid redrawing everything with every change. Instead draw the whole frame at a fixed interval, e.g. every 50ms. Just keep the status of every element in a class and if something changes just change the data value. Due to the fixed redrawing interval the display will pick up any changes at the next redraw.
We are currently using Eclipse Draw2D/GEF for an information page describing a process in our application. This basically consists of a matrix of large squares, each containing a matrix of smaller squares. We originally had all the squares as GEF objects, but because of the large volume of them being shown, we found that this did not scale very well and the view took a very long time to open. We then changed it so that only the large squares are Figures and we then draw the smaller squares using the graphic in paintFigure.
The problem that we are running into is that we still want the tooltip to change depending on which small square you are hovering over. I tried to do this by adding a mouseMotionListener and setting the tooltip, through setTooltip, depending on where the mouse currently is. The problem is that once the tooltip is displayed, it does not change any more when setTooltip is called.
Does any one know of an alternative way of doing this? Is there a way of getting the viewpart's PopupHelper and using that? Any help would be appreciated.
Thanks
Hmnn.. interesting problem. Since you paint your own Grid within the Figure, I would think that you have two options.
Try posting SWT events to fool Eclipse. I'd try a focus lost followed by a focused gained, to trigger tooltip machinery, at which point you could get the coordinates and display the appropriate contents.
Don't use the Figure#getTooltip strategy at all. Just show your own composite.
To dynamically change the tooltip, you can hold an instance of the tooltip Figure in your parent Figure. In the constructor of the parent Figure, create a new tooltip Figure (e.g. a Label) and use setToolTip() method to set the tooltip Figure to parent Figure.
When data model is changed, the updated tooltip text/icon can be set to the tooltip Figure. Then you just call setToolTip(tooltipFigure) method again.
You can have a method like:
protected Label toolTipLabel;
protected void updateToolTip(String text, Image icon){
toolTipLabel.setText(text);
toolTipLabel.setIcon(icon);
setToolTip(toolTipLabel);
}
The updateToolTip() method can be invoked in parent Figure's conturctor to initialize the tooltip. And this method can be invoked each time after the data model is changed.
I encountered the same problem in my code and solved it with that method. In my code, I invoked the updateToolTip() in the parentFigure.paintFigure() method.
I have to use a GUI Element that draws a picture at a specific screen position.
If the user selects this picture there is a border drawn around the Image.
Now we want to include another border that identifies pictures with a specific value for the user.
At the moment the Element looks at his internal state if it is selected and then decides how to draw itself.
graphic.drawImage(icon, x, y, null);
if (selected) {
drawBorder();
}
I don't like the idea of adding another if else to this drawing method.
I thought about creating a new class that inherits the behavior of the element and overwrites the draw method but that means duplicating the whole selected code in every inherited class.
Is there a nice possibility so solve this problem without creating a subclass?
Since you tagged this with design-patterns and you seem to be looking for a pattern-oriented approach, I'd suggest taking a look at the state pattern. The example on the wikipedia page even mentions keeping state while drawing a GUI. Unfortunately, this would mean you'd have to create another class with subclasses and overridden methods.
Is this going to be something that is likely to change? I.e. do you realistically think you're going to be adding new behavior to the drawing (e.g. if the user double clicks, draw a different type of border; if the user right clicks, change the color of the border), or is this it? If you see more behavior being added, I think going ahead and taking a more OO approach is wise. If it's just these two cases, I'd say just add and else if statement.
What do you have against if-else?
It makes less sense to me to create a whole new object for the selected item than to check a flag in the drawing function.
one possibility is to allow your drawBorder() method to take parameters:
private void drawBorder(boolean isSelected, boolean hasSpecialValue);
this method can determine which type of border to draw.