Design: extend JPanel twice or pass JPanel as parameter? - java

I have design issue here. There two options which sound possible to implement but I don't like neither one.
I need to provide two functionality in my JPanel.
draw several lines
draw several strings
ads
Approach extend twice
If I would need only to draw lines then I can just copy-past solution from the following answer.
Draw a line in a JPanel with button click in Java
public class LinePanel extends JPanel {
...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
...
But since I need to add second functionality I would need to do something like this
public class LineStringPanel extends JPanel {
which would leave LinePanel just useless intermediate class.
Create two classes LineDrawer and StringDrawer and pass JPanel as parameter to some method which would perform drawing. The problem here that I would need to call which is not recommended.
Performing Custom Painting
Graphics g = panel.getGraphics();
What do you think and can recommend?
UPD:
Inside the JPanel there are numerious JLabels as child which represent units and traits.
The lines are relation between some traits of units and Strings are kind of notifications for some actions.
So I want to show String on the top(front) of child JLabels.
Also JPanel is inside JScrollPane.

If you need to draw strings, you can do so directly in the paintComponent method (and assuming you don't need anything too fancy, it's pretty easy):
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
...
g.drawLine(p1.x, p1.y, p2.x, p2.y);
...
g.setColor(Color.black);
g.drawString("My Text", 0, 20);
}
Then you could use your trashgod's solution with hardly any changes.
Remember that the coordinates are of the baseline of the text - so if you used 0,0 it wouldn't display on screen.

Related

How to draw an image over JPanels

I have a Battleship game in which I am trying to draw the ships, hits, and misses on the Grid object. Grid is an instance of JPanel with many Blocks. Blocks are JPanels also but are attributes of the Grid. The ships are being drawn on the Grid but under the Blocks. Is it possible to draw over the Blocks? I tried the Glass Pane and it didn't work too well. Any other solutions?
Is it possible to draw over the Blocks? I tried the Glass Pane and it
didn't work too well. Any other solutions?
Yes, a non-recommended but sometime useful approach is to use an extended JPanel and override the paint(Graphics g) function:
Class MyGridPane extends JPanel
{
#Override
public void paint(Graphics g) {
super.paint(g); // <----- don't forget to call this
// then anything you draw will appear above the child component's
Graphics2D g2d = (Graphics2D)g.create(); // cloning to work, it is safer aproach
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();// disposing the graphics object
}
}
Alternatively you may look into using JLayeredPane to work with a Panel containing your drawn image above the target panel(Grid)'s layer.
Check out How to Use Layered Pane
Blocks are JPanels also but are attributes of the Grid. The ships are
being drawn on the Grid but under the Blocks.
There's a sneaky way to achieve it, but you may need to change your base layout to GridBagLayout.
Basically, you want to add each Block to its own cell but GridBagLayout will allow you to add components that can expand columns and/or rows, allowing to add your ships that expand over Blocks.
This, of course, assumes you ships and effects are based on components

Painting over the top of components in Swing?

I have a JPanel added to a JViewport, and the panel has several other panels added to it. I'm trying to implement a dragging selection, where you can select more than one component by dragging the mouse. The only problem I'm facing is that the selection rectangle is being painted behind the components added to the main JPanel. How can I paint over the top of them?
My structure is as follows: JFrame -> ContentPane -> JLayeredPane -> JScrollPane -> JPanel -> JPanel [].
Design draft for college assignment:
As you can see, the rectangle is behind the other panels.
This is what I'm already doing (on a much simpler level obviously), and Swing paints the rectangle underneath the components added to it.
This is one case where you should override the paint() method of the panel and not the paintComponent() method. Then the custom painting will be done AFTER all the child components have been painted.
Use a Layered Pane:
http://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html
This allows you to create overlapping components.
Use a glass pane to handle the drag painting, and possibly events as well:
http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane
hot really sure what do you really needed and final effect, maybe is there two another ways painting to
1) GlassPane
2) Viewport
you can put that together, carrefully Insets to the visible Rectanle
Without seeing your actual code, it is difficult to say what you are doing wrong. However, I can still say what I would do:
Create a JPanel that represents the whole area where you want to draw, which — of course — contains every component.
Override that panel its paintComponents(Graphics) like this (EDITED, notice the s is now the last character from the method name):
#Override
public void paintComponents(Graphics g)
{ // ^
super.paintComponents(g);
// Draw your selection rectangle:
g.setColor(Color.RED);
g.drawRectangle(selectionRectangle);
}
Okay, this is what I've decided to do in the end:
I'm not sure if this is the best way to do it, but it seems to work okay.
Note: Using MigLayout.
In the constructor of the JPanel lying underneath the colored blocks.
...
this.add(new JPanel() {
#Override
public boolean isOpaque() {
return false;
}
#Override
public void paintComponent(Graphics g) {
if (dragShape != null) {
g.setColor(Colors.SECONDARY);
g.setStroke(new BasicStroke(2));
g.draw(dragShape);
}
}
}, "pos 0 0, width 100%, height 100%", 0);
...
Custom painting on top of Swing components is facilitated by JLayeredPane. This article describes an abstract base class that facilitates overpainting specific areas (like selection rectangles or component bounds).

How to draw shapes inside JPanel?

Referring to my earlier question:
Based on your valuable answers, I choose Java 2D library to cater my requirements.
I completely read the above said library and have full understanding of dealing with the graphics stuff, like what to draw and how to draw etc.Now i only left with one question that how do i draw my required shapes inside JPanel and after drawing all those shapes how do i place that JPanel inside a JScrollPane?
Override paintComponent(Graphics g) method.
Cast Graphics to Graphics2D and use drawShape() method passing all your Shapes
You will typically draw your stuff inside a subclass of JComponent, say, MyComponent.
Create an instance of MyComponent, MyComponent myc = new
MyComponent();
Put that inside a JScrollPane, e.g. JScrollPane jsp =
new JScrollPane(myComponent);
Then add the JScrollpane to the
JPanel (exact code depends on the layout manager)

Threading with Swing

basically, I have a program that has a class to create a basic GUI, and another class that extends Canvas. This Canvas class is added to a JPanel in the usual fashion myPanel.add(object). Now, in this class, I want to have methods to move objects such as rectangles.
My questions are these; is there a way to essentially have this JPanel or its added object (myCanvas) running on a separate thread?
Also, in the following method:
public void paint(Graphics g){
g.setColor(Color.black);
g.drawRect(0, 0, 50, 50);
}
Is there a way to have these operations split into multiple methods? I.e. multiple methods that draw to the Canvas?
Thanks in advance.
Don't use a Canvas is a Swing applicaton. Use a JPanel or JComponent and override the paintComponent() method. Also don't forget the super.paintComponent(g) at the start of the method.
See the section in the Swing tutorial on Performing Custom Painting for more information.
Store a list of drawable objects somewhere (perhaps your Canvas class, but I'd advise that being external to your logic...) and use your other thread(s) to update this list of objects.
Your drawing loop can simply clear your canvas (or at least areas that need to be redrawn) and draw those. Ideally your screen-render should be fast enough to facilitate a complete redraw, caching sub-sections as necessary.

Clearing JPanel

I am making a program in which there is a square that changes its x and y positions when a key is pressed. The square moves but the the old square is still there. How do I remove/clear everything from a panel before I repaint it? Calling removeAll had no effect.
Presumably your code includes custom paintComponent() logic. The key thing to observe is what does your panel look like when you do not override paintComponent()? An empty (or cleared) panel:
Thus the solution is to invoke the paintComponent() method of the parent type on the panel, before executing your custom paintComponent() logic:
public class CustomPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // first draw a clear/empty panel
// then draw using your custom logic.
}
}
I think this should work.
g.clearRect (0, 0, panel.getWidth(), panel.getHeight());
Also, you could keep the old location of the square and just clear that rather than clear the whole background.

Categories

Resources