Why Shouldn't You Extend Jframe and Other Components

Why shouldn't you extend JFrame and other components?

Generally speaking, extending the component tends to be done strictly to use the component. This severely limits your options in unnecessary ways in terms of design, so that your classes can't extend different classes, you can't hide the JFrame's methods causing it to be more difficult to maintain and easier to trigger unexpected bugs when using the class.

Typically the intention is strictly to use the class to draw a frame, and composition is preferred over inheritance.

That being said, subclassing should be fine when you intend your subclass to add project-specific functionality to the Frame (such as convenience methods and the like) where the subclass would be used instead of the Frame itself, but used as a frame in general, not as a view of a specific frame in the application.

Extends JFrame vs. creating it inside the program

Thoughts:

  • Avoid extending JFrame as it ties your GUI to being, well a JFrame. If instead you concentrate on creating JPanels instead, then you have the freedom to use these JPanels anywhere needed -- in a JFrame, or JDialog, or JApplet, or inside of another JPanel, or swapped with other JPanels via a CardLayout.
  • Avoid inheritance in general, especially of complex classes. This will prevent pernicious errors, such as inadvertent method overrides (try creating a JFrame or JPanel that has a getX() and getY() method to see what I mean!).
  • Avoid inheritance of complex classes if you are using an IDE: If you override a complex class, when you call methods on objects of these classes, you will have many, too many, choices of methods offered to you.
  • Encapsulation is good, is and allows for creation of safer code. Expose only that which needs to be exposed, and control that exposure as much as possible.

Extending from JFrame

It makes no difference unless you have another class called JFrame and are importing it instead of javax.swing.JFrame.

That said, as Andrew Thompson said, you shouldn't extend JFrame, you should use an instance.

how to extend JFrame in a class that already extends Thread

Instead of extending either JFrame or Thread, use composition, it is a lot less limiting:

public class MyApplication {
JFrame applicationFrame;

Thread someThread;

MyApplication() {
SwingUtilities.invokeLater(new Runnable() {
@Override void run() {
applicationFrame = new JFrame();

// some more GUI initialization.
applicationFrame.setVisible(true);
}
});

someThread = new Thread(new Runnable() {
@Override void run() {
// do my work.
}
});

someThread.start();
}

public static void main(String... args) {

new MyApplication();
}
}

Rescale a drawing in Java (JFrame)

There are bascially two different approaches for this:

  • You can "scale the whole Graphics"
  • You can scale the actual shapes

The difference may be subtle in some cases, but can be important: When you scale the whole Graphics, then everything will be scaled. Particularly, when you scale it about 2.0, and then draw a line with a width of 1.0, the line will be drawn 2 pixels wide. Whether or not this is desired depends on the application case.

In order to scale the actual shapes, you can not use the drawRect method. Instead you will have to create Shape instances that represent the geometric shapes. You can then create scaled versions of these shapes with AffineTransform#createTransformedShape.

Here is an example that compares both approaches (and corrects some of the other issues that have been in your code). In both cases, the same rectangle with an original size of (10,13) is painted, scaled by a factor of 5.0.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ScalingDrawnObjects
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}

private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ScalingDrawnObjectsPanel p = new ScalingDrawnObjectsPanel();
f.getContentPane().add(p);
f.setSize(600,400);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}

class ScalingDrawnObjectsPanel extends JPanel
{
@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;

Shape rectangle = new Rectangle2D.Double(2, 2, 10, 13);

g.setColor(Color.RED);
drawWithScaledGraphics(g, rectangle);

g.translate(100, 0);

drawScaledObject(g, rectangle);
}

private static void drawWithScaledGraphics(Graphics2D g, Shape shape)
{
AffineTransform oldAt = g.getTransform();
g.scale(5.0, 5.0);
g.draw(shape);
g.setTransform(oldAt);
}

private static void drawScaledObject(Graphics2D g, Shape shape)
{
AffineTransform at = AffineTransform.getScaleInstance(5.0, 5.0);
g.draw(at.createTransformedShape(shape));
}

}

EDIT In response to the comment

The code that I posted is not "complicated". It is as compilcated as it has to be, but not more. You should not extend JFrame and you should not override paint. You should create the GUI on the EDT. You should ...

However, you should not use code like the following, but maybe this is what you're looking for

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.awt.Dimension;

public class Stretch extends JFrame {
int originalHeight = 600;
int originalWidth = 600;
public Stretch() {
super("Stretch");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(originalWidth, originalHeight);
}
public static void main(String[] args) {
Stretch s = new Stretch();
s.setVisible(true);
}
public void paint(Graphics g) {
Dimension size = this.getBounds().getSize();
int rectWidth = 100;
int rectHeight = 130;

g.setColor(Color.white);
g.fillRect(0, 0, size.width, size.height);

g.setColor(Color.black);

int w = rectWidth + size.width - originalWidth;
int h = rectHeight + size.height - originalHeight;
double sx = (double)w / rectWidth;
double sy = (double)h / rectHeight;
double s = Math.min(sx, sy);
int fw = (int)(s * rectWidth);
int fh = (int)(s * rectHeight);
g.drawRect(100, 100, fw, fh);

}
}


Related Topics



Leave a reply



Submit