I found a strange anomaly in Java Swing.
The first JButton added to the UI chronologically always fires when the uses presses the space bar, assuming he hasn't clicked another button before doing that. This behavior even occurs if getRootPane().setDefaultButton(JButton) and JButton.requestFocus() are called.
When requesting focus on a JButton there seem to be at least 2 different kinds of "focus".
One of the "focusses" or highlightings is a dashed rectangle around the text on the button, while the other one is a thicker outline around the specified button.
The button with the dashed outlined text fires whenever the space bar is pressed.
The button with the thick border fires whenever the enter key is pressed.
I prepared a compilable minimal example illustrating this behaviour. There is no key mapping/binding involved at all.
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class ButtonFocusAnomalyExample extends JFrame {
public ButtonFocusAnomalyExample() {
super();
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
int frameWidth = 300;
int frameHeight = 300;
setSize(frameWidth, frameHeight);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int x = (d.width - getSize().width) / 2;
int y = (d.height - getSize().height) / 2;
setLocation(x, y);
setTitle("Any Frame");
setResizable(false);
Container cp = getContentPane();
cp.setLayout(null);
setVisible(true);
new DialogMinimal(this, true); // Runs the Dialog
}
public static void main(String[] args) {
new ButtonFocusAnomalyExample();
}
static class DialogMinimal extends JDialog {
private final JTextField output = new JTextField();
public DialogMinimal(final JFrame owner, final boolean modal) {
super(owner, modal);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
int frameWidth = 252;
int frameHeight = 126;
setSize(frameWidth, frameHeight);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int x = (d.width - getSize().width) / 2;
int y = (d.height - getSize().height) / 2;
setLocation(x, y);
setTitle("Minimal Button Focus Example");
Container cp = getContentPane();
cp.setLayout(null);
JButton bYes = new JButton();
bYes.setBounds(0, 0, 100, 33);
bYes.setText("Yes (Space)");
bYes.addActionListener(this::bYes_ActionPerformed);
JPanel buttonPanel = new JPanel(null, true);
buttonPanel.add(bYes);
JButton bNo = new JButton();
bNo.setBounds(108, 0, 120, 33);
bNo.setText("No (Enter/Return)");
getRootPane().setDefaultButton(bNo); // Set "No" as default button
bNo.requestFocus(); // Get focus on "No" button
bNo.addActionListener(this::bNo_ActionPerformed);
buttonPanel.add(bNo);
buttonPanel.setBounds(8, 8, 400, 92);
buttonPanel.setOpaque(false);
cp.add(buttonPanel);
output.setBounds(8, 50, 220, 32);
cp.add(output);
setResizable(false);
setVisible(true);
}
public void bYes_ActionPerformed(final ActionEvent evt) {
output.setText("Yes"); // Still fires on every space bar press
}
public void bNo_ActionPerformed(final ActionEvent evt) {
output.setText("No"); // Only fires on every return/enter press
}
}
}
This is what it looks like:
The executable code can also be found here.
My questions now are:
What are these different focusses?
How can someone change the focus that shows as a dashed outline around the text of the button so that the space bar and the enter key would fire the event of the "No" button?
The Dialog Focus resource (already referenced in comments and in the accepted solution) shows an easier approach as well.
The simple solution has its drawbacks as they are clearly pointed out in the article, but for the scenario above, where the dialog is completely built from user code (as opposite to using static JOptionPane.showXXX), it will do fine.
The trick is to call pack() on the dialog before it is made visible and it's modality will block any further code execution (and focus requests)
Component c = myDialog.getContentPane();
...
c.add(myYesButton); // 1. Add all components to the dialog
myDialog.pack(); // Call pack() on the dialog
myYesButton.requestFocusInWindow(); // Request focus after pack() was called
myDialog.setVisible(true); // Show the dialog
Regarding question 1: "What is the difference between focus on a button represented by a dashed outline and one with a thick continous outline?
Answer: There are no 2 kinds of "focus". Both methods do what their respective names say:
JButton.requestFocus() (better yet JButton.requestFocusInWindow()) requests focus on a button, while getRootPane().setDefaultButton(JButton) sets a selected button, which the LAF handles seperately.
Regarding question 2: "Why does my specific implementation behave like this and how can I achieve the behaviour I want?"
Answer: The modality of the Dialog is the problem. You cannot request focus after setVisible(true) has been called on a modal window.
Possible solutions would therefore be to either:
Set modality to false when creating the Dialog, e.g. with new DialogMinimal(this, false); and get focus by calling bNo.requestFocusInWindow() instead of getRootPane().setDefaultButton(bNo); and/or bNo.requestFocus();, but this is no solution if the Dialog has to be modal.
or
Implement RequestFocusListener found in Dialog Focus as suggested by user camickr.
public DialogMinimal(final JFrame owner, final boolean modal) {
Button bNo = new JButton();
[...]
// bNo.requestFocusInWindow(); // obsolete now
getRootPane().setDefaultButton(bNo); // To fire on enter key
bNo.addAncestorListener(new RequestFocusListener()); // To fire on space bar
[...]
}
Related
I am trying to make a modeless dialog menu in Swing that is displayed upon the press of a button. The dialog contains several menu items. My problem is that the dialog window is much wider than necessary. I am looking for help on setting the window width.
Here's what the output looks like. Notice that the window containing the menu items is much wider than the items themselves. That's what I want to fix.
Here's minimal code that shows this problem:
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test().run();
}
TestDialog testDialog;
private void run() {
JFrame jframe = new JFrame();
JButton jbutton = new JButton("test");
jframe.add(jbutton);
jbutton.setBounds(130, 100, 100, 40);
jframe.setSize(400, 500);
jframe.setLayout(null);
jframe.setVisible(true);
testDialog = new TestDialog(SwingUtilities.windowForComponent(jframe));
jbutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
testDialog.show();
}
});
}
private class TestDialog {
JDialog jdialog;
public TestDialog(Window parent) {
jdialog = new JDialog(parent, "Test", Dialog.ModalityType.MODELESS);
jdialog.setPreferredSize(new Dimension(100, 0));
jdialog.setLayout(new BoxLayout(jdialog.getContentPane(), BoxLayout.Y_AXIS));
JMenuItem jmenuItem1 = new JMenuItem("MenuItem 1");
Dimension jmiDimension = jmenuItem1.getPreferredSize();
System.out.printf("jmenuItem1 is %f x %f%n", jmiDimension.getWidth(), jmiDimension.getHeight());
jdialog.add(jmenuItem1);
jdialog.add(new JMenuItem("MenuItem 2"));
jdialog.pack();
Dimension d = jdialog.getSize();
System.out.printf("jdialog is %f x %f%n", d.getWidth(), d.getHeight());
}
public void show() {
jdialog.setVisible(true);
}
}
}
The program prints this output, showing that the dialog is 324 pixels wide but the menu items are 87:
jmenuItem1 is 87.000000 x 21.000000
jdialog is 324.000000 x 88.000000
I have also tried using the jdialog.setSize() and jdialog.setMaximumSize() methods. And I've tried setting the maximum size of the menu items. None of them seem to have any affect upon the dialog's window size.
I also tried a GridLayout, rather than a BoxLayout - that also made no difference.
I also tried setting the width of the dialog's content pane and layered pane. Still no difference.
I noted that the dialog has no owner nor parent.
testDialog = new TestDialog(SwingUtilities.windowForComponent(jframe));
You don't need to use the windowForComponent(...) method. You already have a reference to the parent frame:
testDialog = new TestDialog( jframe );
Don't attempt to hard code sizes. Each component will determine its own preferred size and the then layout manager will use this information to determine the overall size.
//jdialog.setPreferredSize(new Dimension(100, 0));
A JMenuItem was designed to be used on a JMenu. Instead you should be using a JButton to add to a regular panel.
I don't have a problem with the size. The width/height of the dialog is as expected.
Note I use JDK 11 on Windows 10. When I ran your original code, the dialog had no size since the setPreferredSize() statement caused the height to be 0. So I'm not sure how you get the display shown in your image.
And yes the dialog width is wider than the component added to the frame because there is a minimum width to the dialog to be able to be able to display the title bar even if no components are added to the dialog.
I had been frustrated with some really odd behavior in my code for a while, and after taking time to slowly widdle down my code bit by bit, I finally found the source of the issue.
General overview: using Java Swing, the following code creates a tabbed interface. The first tab that is visible to the user has a button. The second tab has a blue square in the upper left hand corner.
What should happen: Once the program is open, click the button first and then open the other tab. The button calls a function on the other tab, causing the square to move to a new location. Thus, the other tab should show the square in its new location, not the upper left hand corner.
What actually happens: If you click the button first and then open the tab, the square's position is unchanged. It remains in the upper left hand corner, as if the button was never pressed. If you open the tab first, it seems to "prime" the program somehow, so now the button works as expected.
Sure, it seems like a minor annoyance to click on the tab first to ensure the program works, but potentially this is a really big problem. Why is the tab unable to be updated until it is viewed at least once?
Observations: When debugging the code, I can step through the setUnit() function and verify that the square is, in fact, being successfully changed, completely overwriting the previous position. And yet, when I then open the second tab the square's position is now reverted back to where it was previously. If the variables are inspected at that point, it shows the square's original position has remained completely unchanged, as if the setUnit() function was never called. Knowing that these components don't visually update unless repainted, I made sure to add the repaint() function call within the setUnit() function. It really baffles me to wonder where the original values of the square's location are even stored? I can see in the debugger the values are overwritten, so they should completely cease to exist, right?
Code:
DragPanel.java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JPanel;
class DragPanel extends JPanel
{
private static final long serialVersionUID = 1L;
boolean isFirstTime = true;
Rectangle area;
Rectangle rect = new Rectangle(0, 0, 20, 20);
private Dimension dim = new Dimension(400, 300);
public DragPanel() {
setBackground(Color.white);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (isFirstTime) {
area = new Rectangle(dim);
rect.setLocation(0, 0);
isFirstTime = false;
}
g2d.setColor(Color.blue);
g2d.fill(rect);
}
public void setUnit()
{
rect.setLocation(200, 50);
repaint();
}
}
ShapeMover.Java:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
public class ShapeMover {
public ShapeMover() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents(frame);
}
public static void main(String s[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ShapeMover();
}
});
}
private void initComponents(JFrame frame) {
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
tabbedPane.setBounds(10, 93, 426, 527);
frame.getContentPane().add(tabbedPane);
DragPanel shaper = new DragPanel();
shaper.setBounds(0, 79, 420, 420);
JPanel input = new JPanel();
tabbedPane.addTab("Test", null, input, null);
input.setLayout(null);
JButton add = new JButton("Click this");
add.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
shaper.setUnit();
}
});
add.setBounds(201, 64, 65, 23);
input.add(add);
JPanel output = new JPanel();
tabbedPane.addTab("Second", null, output, null);
output.setLayout(null);
output.add(shaper);
frame.pack();
frame.setVisible(true);
}
}
Based on tgdavies comment, I found the solution to the situation.
paintComponent is not part of the construction of the object, but rather is only called whenever the panel is seen. That is, when it is painted. Even calling repaint() is not going to call paintComponent until the panel is seen. Thus, the first time the panel is viewed then this section of code is executed exactly once:
if (isFirstTime)
{
area = new Rectangle(dim);
rect.setLocation(0, 0);
isFirstTime = false;
}
After being executed once, isFirstTime is set to false, and thus doesn't run the section of code again. Thus, calling setUnit() does, indeed, overwrite the square's original position. And then the section of code shown above sets it back to 0,0.
Simply commenting out the line of code that reads rect.setLocation(0, 0); fixes the problem.
look at this simple code:
Main.java :
package CarManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
static int width = 400;
static int height = width / 16 * 9;
static String title = "Car Manager";
JButton viewTables = new JButton("View tables");
JButton clients = new JButton("Clients");
JButton search = new JButton("Search");
JButton viewCars = new JButton("View all");
JButton viewRent = new JButton("Rent a car");
JButton viewBuy = new JButton("Buy a car");
JButton viewAccessory = new JButton("Accessory");
public Main() {
setLayout(null);
setLocationRelativeTo(null);
setTitle(title);
setSize(width, height);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
JLabel background = new JLabel(new ImageIcon("res\\background2.jpg"));
add(background);
background.setSize(width, height);
add(viewTables);
add(clients);
add(search);
viewTables.setBounds(20, 20, 110, 30);
clients.setBounds(20, 70, 110, 30);
search.setBounds(20, 120, 110, 30);
viewTables.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
add(viewCars);
viewCars.setBounds(260, 20, 110, 20);
add(viewRent);
viewRent.setBounds(260, 50, 110, 20);
add(viewBuy);
viewBuy.setBounds(260, 80, 110, 20);
add(viewAccessory);
viewAccessory.setBounds(260, 110, 110, 20);
}
});
viewCars.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
View view = new View();
view.addWindowListener(new WindowPlug(Main.this));
setVisible(false);
}
});
}
public static void main(String args[]) {
new Main();
}
}
View.java:
package CarManager;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class View extends JFrame {
private static final long serialVersionUID = 1L;
int width = 400;
int height = width / 16 * 9;
String title = "View all Cars";
public View() {
setLayout(null);
setLocationRelativeTo(null);
setTitle(title);
setSize(width, height);
setResizable(false);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setVisible(true);
JLabel background = new JLabel(new ImageIcon("res\\background2.jpg"));
add(background);
background.setSize(width, height);
}
}
and WindowPlug.java:
package CarManager;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class WindowPlug extends WindowAdapter {
private Main mainFrame;
public WindowPlug(Main mainFrame) { // when creating an instance of this
// WindowAdapter, tell it with which
// Main Window you are working with
this.mainFrame = mainFrame;
}
public void windowClosing(WindowEvent e) {
mainFrame.setVisible(true);
mainFrame.revalidate();
}
}
when i click view tables and then view all (those are the buttons that work for now)
and the first window hides and a new window appears, now when i close the second window the first one appears visible but the buttons are not visible, i have to hover over with the mouse for them to be visible again. ive tried mainFrame.revalidate(); and
mainFrame.repaint();
but no result
im using windows 8.1 pro
One problem with your code, and I'm not sure if this is the main problem since your code works fine on my system, is that you're calling setVisible(true) on your main window before you've added all your components. It should only be called after all components have been added.
Other problems unrelated to your main question:
You should avoid using null layout. While using null layout may seem to a newbie the better way to create complex GUI's, it's a fallacy, and more you create Swing GUI's the more you learn to respect and use the layout managers and see that these creatures help immensely in creating flexible, beautiful and if need be, complex GUI's. Then you can let them size them selves appropriately by calling pack() prior to setting them visible.
It appears that you really want to use a CardLayout to swap views on one GUI rather than spitting multiple GUI's at the user.
If you absolutely must display a dialog window, then you should use a JDialog, not a JFrame. If you used a modal JDialog, you wouldn't be needing a WindowListener.
Edit
OK, a big problem I see is that you're using null layout and adding a JLabel that covers the whole contentPane, and then adding components to the same contentPane.
Instead, make the JLabel your contentPane, and then add your JButtons, etc to it.
But make sure that the JLabel's opaque property is set to true first.
Edit 2
If you need to use an image as a background image you can:
Put the Image in an ImageIcon, put the Icon in a JLabel, and again use the JLabel as your contentPane. Again, you will need to make the JLabel opaque by calling setOpaque(true) on it. This works well if you don't want to change the size of the image or the window.
If you do need to change the size of the image, better to have a JPanel draw the image in its paintComponent(Graphics g) method, and then use this JPanel as your contentPane.
Once you've created your contentPane, then set its layout and add your components to it.
Then call setContentPane(newContentPane) on your top level window and pass in the new contentPane.
I have only JTabbedPane inside JFrame. JTabbedPane sets its dimensions to biggest page width/height.
As pages has different size is it possible to force JTabbedPane to change its dimensions when selecting other page?
http://grab.by/3hIg
Top one is how it behave now and bottom one is how i want it to behave (i resized frame by hand)
This is fairly simple. It involves dynamic calculation of differences between your pages dimensions and the using them to force preferred size on you JTabbedPane. I did a quick experiment and it worked. So instead of putting a lot of text here - here is the code. It is not perfect but you should get an idea. Questions are welcome, of course.
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
private static int maxW = 0;
private static int maxH = 0;
public static void main(String[] args) {
final JFrame f = new JFrame();
final JTabbedPane tabs = new JTabbedPane();
tabs.add( createPanel(Color.RED, 100, 100), "Red");
tabs.add( createPanel(Color.GREEN, 200, 200), "Green");
tabs.add( createPanel(Color.BLUE, 300, 300), "Blue");
final Dimension originalTabsDim = tabs.getPreferredSize();
tabs.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
Component p = ((JTabbedPane) e.getSource()).getSelectedComponent();
Dimension panelDim = p.getPreferredSize();
Dimension nd = new Dimension(
originalTabsDim.width - ( maxW - panelDim.width),
originalTabsDim.height - ( maxH - panelDim.height) );
tabs.setPreferredSize(nd);
f.pack();
}
});
f.setContentPane(tabs);
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static final JPanel createPanel( Color color, int w, int h ) {
JPanel p = new JPanel();
p.setBackground(color);
p.setPreferredSize( new Dimension(w, h));
maxW = Math.max(w, maxW);
maxH = Math.max(h, maxH);
return p;
}
}
I think another option is to dynamically change the panels of each tab when the tab is selected:
install a listener on JTabbedPane selection
install an empty panel on every tab but the selected tab by default (that contains the real panel for that tab)
in the selection listener:
remove the panel from the previously selected tab (ie, replace it with an empty panel)
change the empty panel by the real panel in the newly selected tab
call pack() on the window/dialog containing the JTabbedPane
Disclaimer: I haven't tested this approach but I believe it should work according to what you want.
Please also note that dynamically changing the size of the dialog based on the selected tab is not very user-friendly from a pure GUI viewpoint.
How about this?
tabbedPane.addChangeListener(new ChangeListener(){
#Override
public void stateChanged(ChangeEvent arg0) {
Component mCompo=tabbedPane.getSelectedComponent();
tabbedPane.setPreferredSize(mCompo.getPreferredSize());
BasicFrame.this.pack();
}
});
I am building a Java Swing application that needs to support both an embedded browser and ActiveX. The easy way to do this seemed to be to use JDICplus, which just embeds IE in your application. That would have covered both requirements.
I also need to overlay some buttons on top of this browser view so the user can navigate between views. To do that, I have a JLayeredPane to which I add views, and at a higher layer, buttons. This works in my pure Java views. However, on my Internet view, the Internet draws on top of the buttons. In other words, it doesn't seem to respect the JLayeredPane. I'm guessing this is because it is a native component and not a Java component.
To be sure, I put the Internet pane into a JInternalFrame, and the buttons in the other, and put both of the internal frames into a JDesktopPane. When I drag the button frame on top of the Internet frame, the Internet frame jumps to the foreground and covers the other frame. It's as if the embedded IE steals the focus and puts itself in the forefront of my other windows.
My question is this: is there any way to draw Java components on top of these Windows/IE components reliably? Or, am I not going to get anywhere mixing Java with IE? Are there other options to meeting my requirement of an embedded browser and ActiveX support (which technically, could be a different view--in other words, I could have an Internet view and another view that just supports ActiveX). I'm open to suggestions. I have looked at other free browser components for Java, and as everyone will tell you, it's discouraging.
Check out Sun's article on mixing heavy and light components - since JDICPlus basically embeds IE into your app, it's a heavyweight component.
You may be able to place buttons over the browser window by using other heavyweight components (i.e. AWT Button), or do something like place the button into a JPopupMenu placed over the browser with setDefaultLightWeightPopupEnabled(false) set on it to make it heavyweight.
Edited
I wrote an example using JPopupMenu to display a JButton over a heavyweight component - JPopupMenu works, but it does have built in behavior to close the menu when the popup or components in the popup lose focus. I added a MouseMotionListener to the heavyweight component to show the popups when the mouse entered a bounding box near where the buttons should be. Not sure if this works for you as the buttons aren't always shown.
Including a code example and screenshot -
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
public class LightHeavy extends JFrame {
private Component heavyweightComponent;
private JPopupMenu backButton, forwardButton;
public LightHeavy() {
super("LightHeavy");
heavyweightComponent = buildHeavyweightComponent();
heavyweightComponent.setBackground(Color.ORANGE);
heavyweightComponent.setSize(640, 480);
getContentPane().add(heavyweightComponent, BorderLayout.CENTER);
ImageIcon backArrow = new ImageIcon("left_arrow_128.png");
backButton = buildPopup(backArrow);
ImageIcon forwardArrow = new ImageIcon("right_arrow_128.png");
forwardButton = buildPopup(forwardArrow);
heavyweightComponent.addMouseMotionListener(new MouseInputAdapter() {
public void mouseMoved(MouseEvent e) {
Rectangle backHotSpot = new Rectangle(0, 0, 200, 200);
Rectangle forwardHotSpot = new Rectangle(heavyweightComponent.getWidth() - 200, 0, 200, 200);
if (backHotSpot.contains(e.getPoint())) {
backButton.show(heavyweightComponent, 0, 0);
} else if (forwardHotSpot.contains(e.getPoint())) {
forwardButton.show(heavyweightComponent,
heavyweightComponent.getWidth() - forwardButton.getWidth(), 0);
}
}
});
}
private Component buildHeavyweightComponent() {
return new Canvas() {
public void paint(Graphics og) {
super.paint(og);
Graphics2D g = (Graphics2D)og;
String big = "Heavyweight Component";
g.setFont(getFont().deriveFont(20F));
Rectangle2D bigBounds = g.getFontMetrics().getStringBounds(big, g);
g.drawString(big,
(this.getWidth() - (int)bigBounds.getWidth()) / 2,
(this.getHeight() - (int)bigBounds.getHeight()) / 2);
String little = "(assume this is JDICplus)";
g.setFont(getFont().deriveFont(10F));
Rectangle2D littleBounds = g.getFontMetrics().getStringBounds(little, g);
g.drawString(little,
(this.getWidth() - (int)littleBounds.getWidth()) / 2,
(this.getHeight() + (int)littleBounds.getHeight()) / 2);
}
};
}
private JPopupMenu buildPopup(Icon icon) {
JButton button = new JButton(icon);
JPopupMenu popup = new JPopupMenu();
popup.add(button);
popup.setBorderPainted(false);
popup.setLightWeightPopupEnabled(false);
return popup;
}
public static void main(String[] args) {
JFrame f = new LightHeavy();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
Here's a screenshot with the JButton on the left showing - note that you also won't be able to do any cool transparency effects, as you're dealing with heavyweight components.