So I am creating this applet which I want to have full on swing components in it. I have looked at all the docs, I have made the applet, and I can get something to show up in it if I override the update(Graphics g) method, but simply adding components to the contentPane doesn't seem to be doing it! What am I doing wrong?
import javax.swing.JApplet;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import org.steephill.kindlab.LabApp;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
public class ClientApplet extends JApplet {
ClientTreePanel treePanel;
public void destroy() {
// Put your code here
}
public String getAppletInfo() {
return "KindLab Client Applet";
}
public void init() {
try {
LabApp.initializeHibernate();
if (!LabApp.authenticate("user", "pass")) {
JOptionPane.showMessageDialog(this, "authentication failed");
} else {
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn't successfully complete");
}
}
} catch (Exception ex) {
JOptionPane.showMessageDialog(this, "error intitializing applet\r\n" + ex.getMessage());
}
}
protected void createGUI() {
treePanel = new ClientTreePanel();
treePanel.setVisible(true);
getContentPane().add(new JLabel("TESTING!"));
getContentPane().add(treePanel);
System.out.println("THIS DOES RUN");
}
public void start() {
// Put your code here
}
public void stop() {
// Put your code here
}
/* if I uncomment this method, it WORKS and I get "Hello World!"
public void paint(Graphics g) {
super.paint(g);
g.drawString("Hello World!",25,25);
}
*/
}
Please, help! And thank you!
Joshua
I see several problems with your code here:
you do not call pack() at the end of your GUI setup
you add several components to the applet's content pane, but without any layout constraints. The default content pane usually is a BorderLayout, so adding two components without any constraints will probably only put the ClientTreePanel on top.
Since you do not call pack(), the layout will not be calculated, which for your case probably results in nothing being displayed (you did not provide the code for ClientTreePanel).
You shouldn't have to call pack() - the layout will be calculated when the component first becomes realized, which happens when you call pack - but also when the component first becomes visible.
The "adding components without constraints" is on the right track - you should change the code adding components to the content pane to :
getContentPane().add(new JLabel("TESTING!"), BorderLayout.NORTH);
getContentPane().add(treePanel, BorderLayout.CENTER);
The other problem is why your ClientTreePanel component isn't showing up - it could be sizing, or a layout problem, or other things - but without seeing that code, it would just be guesses.
Try to delete your paint method and you'll see it works. The problem might be the fact that since you've got a paint method all the changes are made through it. It's weird though because it does display a JButton.
Related
I'm having an error when trying to add a component to a JFrame.
This is the first class:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class FrameG extends JFrame
{
private static final String MOVE_UP = "move up";
public static int frameID = 1;
private static JFrame window = new JFrame();
private static openWin frame = new frame01();
public static void main(String[] args) {
window.setSize(1500,900);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
window.setResizable(true);
frame.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), MOVE_UP);
frame.getActionMap().put(MOVE_UP, new movement());
mainloop();
}
private static void mainloop()
{
window.removeAll();
switch(frameID)
{
case 1:
frame = new frame01();
frame.setLayout(new FlowLayout());
System.out.println(frame);
window.add(frame);
break;
default:
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(FrameG.class.getName()).log(Level.SEVERE, null, ex);
}
mainloop();
}
}
class movement extends AbstractAction
{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("hi");
}
}
and the second class (it extends a class with an abstract paint method that extends JComponent):
import java.awt.Graphics;
import java.awt.*;
import javax.swing.JComponent;
import java.awt.geom.*;
public class frame01 extends openWin{
#Override
public void paint(Graphics g) {
Graphics2D pic = (Graphics2D) g;
pic.setBackground(Color.BLACK);
}
}
The error may be the invalid part, but i'm not sure what it is:
frameg.frame01[,0,0,0x0,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=0,maximumSize=,minimumSize=,preferredSize=]
You code shows a distinct lack of understanding into how Swing works
This...
private static void mainloop()
{
window.removeAll();
switch(frameID)
{
case 1:
frame = new frame01();
frame.setLayout(new FlowLayout());
System.out.println(frame);
window.add(frame);
break;
default:
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(FrameG.class.getName()).log(Level.SEVERE, null, ex);
}
mainloop();
}
Is a bad idea of two reasons, the first been that it will eventually generate a StackOverflowException, the second been that it violates the single thread rules of Swing.
Normally, a while-loop would generally be better, but as you're dealing with Swing based components you should consider using either a Swing Timer or SwingWorker, depending on what you are hoping to achieve.
Constantly adding and remove components also seems like a weird idea, but there's no context to the question to know what it is you're hoping to achieve. Having said that, as a general rule, if you want to switch between views a CardLayout is generally considered the preferred solution
This...
public class frame01 extends openWin{
#Override
public void paint(Graphics g) {
Graphics2D pic = (Graphics2D) g;
pic.setBackground(Color.BLACK);
}
}
is simply doing nothing, other then breaking the paint chain, which could cause no end of weird paint artefacts to be generated. All you code does if temporarily changes the background color of the Graphics context, but since you don't paint anything with it, it's effectively meaningless
As a general rule, it's recommended to override the paintComponent method of Swing components (and call super.paintComponent before you do any custom painting).
I would highly recommend that you take a look at:
Painting in AWT and Swing
Performing Custom Painting
Concurrency in Swing
How to use Swing Timers
Worker Threads and SwingWorker
How to Use CardLayout
Your code has lots of problems. The line private static openWin frame = new frame01(); seems fishy as I said in my comment. But its not the worst part:
THIS:
private static void mainloop()
{
window.removeAll();
switch(frameID)
{
case 1:
frame = new frame01();
frame.setLayout(new FlowLayout());
System.out.println(frame);
window.add(frame);
break;
default:
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(FrameG.class.getName()).log(Level.SEVERE, null, ex);
}
mainloop();
}
Is BAD! And it probably breaks since you are constantly creating a new frame01() and adding it to your window.
Also DO NOT override paint but paintComponent. Another thing I dont get is why override it in a separate class and not in openWin itself.
Another thing, DO NOT SLEEP THE MAIN THREAD, if you really must then run your own and put IT to sleep.
What is the purpose of this code? I'm trying to understand it so I can help you redesign it.
PS: not really an answer, just a bit longer than a comment.
Never use a Thread and it's start and stops as a timer. Use javax.swing.Timer instead. Also you've created a recursive function to implement an infinite loop which is very wired and prone to fail. Swing has it's own thread and when you mix it up with another threads unconsciously it transform your code to a monster we are all afraid of.
What I want is entirely WindowsLookAndFeel, and I have this code in my JFrame.
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception ex) {
ex.printStackTrace();
}
However, what I got it part Windows, part Metal (the cross platform style which looks awful. I think I know where the problem is:
The abnormal part(metal part) is a JPanel, and it is not originally built in the JFrame. I have a button. If pressed, the JPanel will be added to the JFrame.
if (((JToggleButton) e.getSource()).isSelected()) {
getContentPane().add(Console.getInstance(), BorderLayout.EAST);
} else {
remove(Console.getInstance());
}
revalidate();
pack();
But still, I don't know why this happens, and how to solve it.
You need to define the look and feel outside of the EDT. Create a class having a main method. In that method set the LAF and then display the app:
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch(Exception e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jFrame.pack();
jFrame.setVisible(true);
}
});
What I am looking to do is have the user to be able to change perspectives from a KeyListener. If the user hits the specified key, than the perspective should change. Any ideas?
Even if I override the methods they still do not work. I have also tried KeyAdapter
package com.development.gameOne.environment.component;
import java.applet.Applet;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import com.development.gameOne.environment.applet.drawing.Perspective;
import com.development.gameOne.environment.applet.perspectives.p1.FirstPerspective;
import com.development.gameOne.environment.applet.perspectives.p2.SecondPerspective;
public class Component extends Applet implements KeyListener {
private static final long serialVersionUID = 1L;
private Dimension size = new Dimension(1280, 720);
private ArrayList<Perspective> perspectives = new ArrayList<Perspective>();
private boolean running = true;
private boolean switchPerspective = false;
public Component() {
setPreferredSize(size);
loadPerspectives();
addKeyListener(this);
setFocusable(true);
setVisible(true);
start();
}
private void loadPerspectives() {
perspectives.add(new FirstPerspective());
perspectives.add(new SecondPerspective());
}
public static void main(String[] args) {
new Component();
}
#Override
public void paint(Graphics g) {
while (running) {
for (Perspective p : perspectives) {
System.out.println(p.getPerspective());
while (!switchPerspective) {
System.out.println("Rendering");
p.start(g);
sleep(100);
}
switchPerspective = false;
}
sleep(10);
}
}
public static void sleep(int renderSpeed) {
try {
Thread.sleep(renderSpeed);
}
catch (Exception e) {}
}
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_SHIFT:
System.out.println("KeyPressed");
switchPerspective = true;
break;
}
}
public void keyTyped(KeyEvent e) { }
public void keyReleased(KeyEvent e) {}
}
The program runs, but doesn't switch perspectives. I cannot seem to get the KeyListener
to work at all. I really have no idea what to do.
I don't think the issue is with your KeyListener, but is with your paint process
#Override
public void paint(Graphics g) {
while (running) {
for (Perspective p : perspectives) {
System.out.println(p.getPerspective());
while (!switchPerspective) {
System.out.println("Rendering");
p.start(g);
sleep(100);
}
switchPerspective = false;
}
sleep(10);
}
}
This will block the Event Dispatching Thread, preventing it from ever been able to process new events coming into the system
Take a look at Painting in AWT and Swing for details about how painting works in AWT.
The (simple) solution, in this case, would be to provide a other Thread which handles the timing between updates and simple call repaint when you want the UI updated.
A better solution would be take take advantage of the a BufferStrategy instead. It still require a Thread, but stops you from breaking the painting chain.
As a side note. AWT Applets are woefully out-of-date and were replaced by JApplet before 2000. Having said that, I would recommend against using applets at all, as they have enough problems which only increases the difficulty of starting development and focus on something like a JPanel added to an instance of a JFrame instead.
Take a look at Performing Custom Painting and Creating a GUI With JFC/Swing
I'd also drop the use of KeyListener as soon as you can in favour of Swing's Key bindings API. See How to Use Key Bindings for more details
I'd also avoid calling your applet Component, there already is a class called Component and this is just going to confuse matters...
And applets, definitely, should not have a main method. They are expected to be loaded by the browser directly and have a different, defined, life cycle.
i know multithreading a bit but not in vast and i think the problem is of multithreading. I am calling a method to set label's text by invoking a new thread and leaving it blank after a specified time. I am getting the desired output every time but not only the place which i am going to show you by my piece of code. I am expecting that message should be set and disappeared after the specified time and the window should be minimized after that time. But what actually happening is when it is going to the other thread main thread execution starts and goes for sleep for 5 sec and the message is not appearing and after 5 sec window is getting minimized without showing the message which i am setting on the label.
(Main thread)
Validation.setMessageOnLabel("Username and password has been copied", jLabel15,1.5F);
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
Logger.getLogger(PasswordManager.class.getName()).log(Level.SEVERE, null, ex);
}
setState(ICONIFIED);
validation.java (setMessageOnLabel())
static public void setMessageOnLabel(final String msg, final JLabel label, final float time)
{
new Thread(new Runnable() {
#Override
public void run() {
label.setText(msg);
try {
Thread.sleep((long) (time*1000));
} catch (InterruptedException ex) {
Logger.getLogger(PasswordManager.class.getName()).log(Level.SEVERE, null, ex);
}
label.setText("");
}
}).start();
}
Since you're calling setState() directly, I assume the first code snippet is part of a JFrame. In that case you're most probably sending the event dispatch thread to sleep for 5 seconds and thus prevent screen updates during that time.
Put the sleep into another thread or use a swing worker instead and call setState() on the EDT in the worker's callback method, since setState() is not labelled as thread-safe and calling it on a thread other than the EDT might result in unexpected behavior.
From the linked tutorial:
Some Swing component methods are labelled "thread safe" in the API specification; these can be safely invoked from any thread. All other Swing component methods must be invoked from the event dispatch thread. Programs that ignore this rule may function correctly most of the time, but are subject to unpredictable errors that are difficult to reproduce.
Don't use Thread.sleep(5000);, that block EDT.
For that purposes you can use swing Timer, examine next example:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class TestFrame extends JFrame {
private JLabel lbl;
public TestFrame() {
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void init() {
lbl = new JLabel(" ");
JButton setText = new JButton("setText");
setText.addActionListener(getActionListener());
add(lbl);
add(setText,BorderLayout.SOUTH);
}
private ActionListener getActionListener() {
return new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
lbl.setText("wait...");
Timer t = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
lbl.setText("");
setState(JFrame.ICONIFIED);
}
});
t.setRepeats(false);
t.start();
}
};
}
public static void main(String args[]) {
new TestFrame();
}
}
When dealing with Swing components you shuld not use threads like that. Launch your own SwingWorker instead.
public class MySwingWorker extends SwingWorker<Object, Object> {
#Override
public Object doInBackground() {
//your code here
//dont forget to repaint changed component or validate parent of it,
//if your text dont shows up.
return null;
}
}
you can also execute your own runnable via SwingUtilites
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//again your code here...
}
});
Is there a way to close a JDialog through code such that the Window event listeners will still be notified? I've tried just setting visible to false and disposing, but neither seem to do it.
Closing a window (with dispose()) and hiding it (with setVisible(false)) are different operations, and produce different events -- and closing it from the operating system is yet another different operation that produces yet a different event.
All three will produce windowDeactivated to tell you the window's lost focus, but dispose() will then produce windowClosed, while closing from the OS will first produce windowClosing. If you want to handle both of these the same way, you can set the window to be disposed when closed:
window.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
In general, setVisible(false) implies that you might want to use the window again, so it doesn't post any window events (apart from windowDeactivated). If you want to detect the hiding of a window, you need to use a ComponentListener;
window.addComponentListener(new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent e) {
System.out.println("componentHidden()");
}
})
Note though that this will pretty much only work for explicit setVisible() calls. If you need to detect hiding more generally, you can use a HierarchyListener, but it's probably more trouble than it's worth.
window.addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
System.out.println("valid: " + window.isValid());
System.out.println("showing: " + window.isShowing());
}
});
Note that when you dispose a window you'll get a couple of HierarchyEvents, first for hiding and then for invalidation, but when you hide it with setVisible() it's still valid, so you won't get the invalidation.
I don't seem to have your problem. When I use the code below windowDeactivated() is called for either setVisible( false ) or dispose() and windowClosed() is also called for dispose().
ClosingDialog.java:
public class ClosingDialog extends JDialog {
public ClosingDialog(Frame owner, String title, boolean modal) {
super(owner, title, modal);
JPanel contentPanel = (JPanel) this.getContentPane();
JButton setVisButton = new JButton("setVisible( false )");
setVisButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ClosingDialog.this.setVisible(false);
}
});
JButton disposeButton = new JButton("dispose()");
disposeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ClosingDialog.this.dispose();
}
});
contentPanel.setLayout(new FlowLayout());
contentPanel.add(setVisButton);
contentPanel.add(disposeButton);
this.addWindowListener(new WindowListener() {
public void windowActivated(WindowEvent e) {
System.out.println("windowActivated");
}
public void windowClosed(WindowEvent e) {
System.out.println("windowClosed");
}
public void windowClosing(WindowEvent e) {
System.out.println("windowClosing");
}
public void windowDeactivated(WindowEvent e) {
System.out.println("windowDeactivated");
}
public void windowDeiconified(WindowEvent e) {
System.out.println("windowDeiconified");
}
public void windowIconified(WindowEvent e) {
System.out.println("windowIconified");
}
public void windowOpened(WindowEvent e) {
System.out.println("windowOpened");
}
});
this.setSize(300, 300);
}
}
Dispatch a windowClosing event to the Window. Check out the ExitAction example from the Closing an Application entry.
Untested suggestion:
Have you tried getWindowListeners() and then iterating around to fire windowClosed() to each of the WindowListeners?
EDIT: the above suggestion is wrong. Keeping it for posterity.
I'm afraid calling dialog.dispose() works fine for me in my simple example.
I wanted to fire a windowClosing event from the code (just as if the user clicked the X), because I have an extra close button in the JDialog and want the same WindowListener (that I implemented using a WindowAdapter) to be run when the X is clicked and when the button is clicked. Running dispose() only fires windowClosed, not windowClosing, and I want a message to appear before the window is closed, for confirmation. I also didn't manage to fire windowClosing via JDialog's method processWindowEvent since it is protected.
Here is how I got it working though:
WindowAdapter adapter = (WindowAdapter)jdialog.getWindowListeners()[0];
adapter.windowClosing(new WindowEvent((Window)jdialog, WindowEvent.WINDOW_CLOSING));
Hope that helps someone.