I have tried this code to draw a string on my frame using KeyListener interface such that whenever I hit a typeable key on keyboard, it should appear on frame but it doesn't work even though there are no errors.
Can someone tell what's the mistake?
Below is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class KeyevntFrame2 extends Frame {
Button b = new Button("ok");
Button b1 = new Button("hey");
char ch;
String s = "";
public KeyevntFrame2() {
setTitle("understand key events");
setSize(800, 600);
addKeyListener(new KeyHandler());
setFont(new Font("Arial", Font.PLAIN, 35));
setForeground(Color.BLACK);
add(b);
add(b1);
b.setBounds(200, 200, 100, 100);
b1.setBounds(200, 700, 100, 100);
setLayout(null);
b.addActionListener(new KeyHandler());
b1.addActionListener(new KeyHandler());
}
class KeyHandler implements KeyListener, ActionListener {
public void keyPressed(KeyEvent e) {
ch = e.getKeyChar();
s = s + ch;
repaint();
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public void paint(Graphics g) {
g.drawString(s, 300, 200);
g.setFont(new Font("Arial", Font.PLAIN, 35));
}
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(b1, "thank you for using java");
}
}
public static void main(String a[]) {
KeyevntFrame2 f = new KeyevntFrame2();
f.setVisible(true);
}
}
Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or combinations of them along with layout padding and borders for white space. This advice is especially relevant to this GUI, given that the frame does not have enough height to display the second button.
Don't mix AWT (Frame) and Swing (JOptionPane) components in one GUI. Choose a GUI toolkit and stick with it.
Always use #Override notation when changing the behavior of existing methods or implementing the methods of an interface. Doing so would have warned you that neither the KeyListener nor ActionListener interfaces define a public void paint(Graphics) method!
Defining a combined KeyListener and ActionListener does not make much sense, and has confused you into thinking that calling Button.addActionListener(..) with the combined listener will also have the effect of adding it as a KeyListener. It won't.
new Font("Arial", Font.PLAIN, 35) for cross-platform robustness, that should be new Font(Font.SANS_SERIF, Font.PLAIN, 35) (e.g OS X will typically not have the Arial font installed, and users would prefer to see Helvetica in any case.)
It is not necessary to set the font of the frame, and also the font in the paint method. Just do it once in the frame.
Since the frame itself is not focusable, calling addKeyListener(..) will have no effect. Better to use Swing and implement key bindings in any case.
When custom painting, always call the super method first.
Swing and AWT GUIs should be started on the EDT.
"it doesn't work even though there are no errors." There are plenty of errors in the code seen above, it's just that they are neither compilation errors, nor run-time errors that throw exceptions. Plenty can still go wrong with code even if the compiler or virtual machine does not identify them. This is why 'cut & paste' coding sans understanding what the code does, never works. Hit the tutorials and read the Java docs.
Related
I am working on a code that will generate a random number when you press a button and output that number. I have wrote this code and it compiles but when I press the button nothing works. Can someone please help. Here is some of my code.
public class slotmachine extends JApplet {
JButton b1 = new JButton("START");
JPanel p;
int Int1;
public slotmachine() {
init();
}
public void init() {
this.setLayout(null);
this.setSize(1000, 1000);
JButton b1 = new JButton("START");
b1.setBounds(100, 100, 100, 100);
getContentPane().add(b1);
repaint();
}
public void run() {
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Random random1 = new Random();
int Int1 = random1.nextInt(11);
}
});
}
public void paint(Graphics g) {
g.drawString("Your number is" + Int1, 30, 30);
}
}
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
You create a local variable of Int1 within the ActionListener for the button. This has no relationship to the Int1 of the class.
You never tell the UI to update
You break the paint chain by failing to call super.paint (be ready for some seriously weird and wonderful graphics glitches)
You've made the same mistake with b1 as you have with Int1. You create an instance level field, but shadow it with a local variable in init, meaning when start is called, b1 is null, which will result in a NullPointerxception
Instead, add a JLabel to your applet, use it's setText method to display the random value
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Random random1 = new Random();
int Int1 = random1.nextInt(11);
lable.setText(Integer.toString(Int1));
}
});
Also, if possible, I'd avoid using JApplet, they have their own set of issues which can make life more difficult then it needs to be when learning the Swing API. Instead, try using a JPanel for your main container and then add it to an instance of a JFrame.
Also, take a look at:
Understanding Class Members for more information about local and class/instance context for variables
How to Use Labels
Why is it frowned upon to use a null layout in SWING? and Laying Out Components Within a Container
And if your really interested in how painting works, Performing Custom Painting and Painting in AWT and Swing
for more details
I am trying to set up and have my jpanel's background color change, everytime when focus is gained and lost, but I can't seem to get it right. Any kind of help would be greatly appreciated. Here is what I have so far:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class 7UpsPanel extends JFrame {
private JPanel jpanel = new JPanel();
public MyFrame() {
super("Lab 5 - Part 1");
//setLayout(new FlowLayout());
setLocation(100, 100);
setSize(500,500);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FocusListener focused = new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
// TODO Auto-generated method stub
setBackground(Color.BLACK);
setBackground(Color.YELLOW);
}
#Override
public void focusLost(FocusEvent e) {
// TODO Auto-generated method stub
setBackground(Color.WHITE);
}
};
jpanel.addFocusListener(focused);
add(jpanel);
}
}
You have a sequence of problems here. I'll go through them one by one.
First of all, I see that you have a class named "7UpsPanel". I'm not sure which compiler is even allowing this, but officially it's against the Java Specification for any identifier to begin with a literal number (against most specifications, actually). It would be better to call it "SevenUpsPanel". This is a little tangential to your question, though.
Andrew Thompson is right, that JPanels are not, by themselves, focusable. This is by design. You can change that (on a panel-by-panel basis) with the setFocusable(boolean) method, which should go right before your addFocusListener(…) call.
Additionally, your setBackground(…) calls are referencing the JFrame's setBackground(), not your panel's. To properly change the color of the panel, they should look more like:
jpanel.setBackground(Color.BLACK);
Lastly, changing the background color doesn't qualify as an invalidation interrupt. You have to trigger it manually, or rather, write in the automation. This means that, at the end of each FocusListener method, you must have (at minimum):
repaint();
Or, any other method known to internally trigger a repaint. This method calls paint(Graphics g) and paintComponents(…) in the necessary order to redraw your frame.
Lastly, don't add the panel like that. You would, in this instance, want to make it your content pane. Adding the pane the way you are provides no guarantee of it having a visible area; content panes take up the area of the frame (minus insets of course).
Lastly, those two TODOs are reminders that you haven't written anything into the auto-generated methods. You clearly have, and to leave them in, well, that just defeats the point of it all.
Here's my remake of your program, just to give you an idea what I mean:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SevenUpsPanel extends JFrame {
public static void main(String[] args) {
new SevenUpsPanel();
}
private JPanel jpanel = new JPanel();
public SevenUpsPanel() {
super("Lab 5 - Part 1");
setLocation(100, 100);
setSize(500, 500);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FocusListener focused = new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
// jpanel.setBackground(Color.BLACK); // Assuming an old command?
jpanel.setBackground(Color.YELLOW);
repaint();
}
#Override
public void focusLost(FocusEvent e) {
jpanel.setBackground(Color.WHITE);
repaint();
}
};
jpanel.setFocusable(true);
jpanel.addFocusListener(focused);
setContentPane(jpanel);
}
}
JPanels are tricky, they aren't like other JComponents. Take a look at the documentation, comparing JPanel's inheritance with, say, JButton, when you have a moment, and I'm sure you'll see why. They make great canvases but when it comes to focus listening, it's often better to use something like an undecorated JButton or even a JTextField.
Best of luck, and I hope this helps.
I have recently been making a game and came across a problem I could not solve. My problem is with removing the content pane of a JFrame and setting as something else. While this works, the KeyListener in the class of the content pane does not work unless I change the primary window on the computer to something else then back to the JFrame.
I replicated the problem in a smaller amount of code than what is was originally:
import java.awt.*;
import java.awt.event.*;
import javax.awt.swing.*;
public class TheFrame extends JFrame{
private JButton play;
private FirstPanel fp;
private SecondPanel sp;
public TheFrame(){
setSize(800, 600);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
fp = new FirstPanel();
setContentPane(fp);
setVisible(true);
}
public static void main(String args[]){
TheFrame tf = new TheFrame();
}
class FirstPanel() extends JPanel{
private boolean test = false;
public FirstPanel(){
play = new JButton("play");
play.addActionListener(new PlayListener());
add(play);
}
public void paintComponent(Graphics g){
if(test == true){
sp = new SecondPanel();
removeAll();
revalidate();
setContentPane(sp);
}
}
class PlayListener implements ActionListener{
public void actionPerformed(ActionEvent e){
test = true;
repaint();
}
}
}
}
Here is also the code for the class SecondPanel:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
public class SecondPanel extends JPanel implements KeyListener{
private int draw = 0;
public SecondPanel(){
addKeyListener(this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawString("press f to draw circles", 90, 40);
if(draw > 0){
for(int i = 0; i < draw; i++){
g.drawOval((i*100)+100, (i*100)+100, 100, 100);
}
}
}
public void keyTyped(KeyEvent e){
if(e.getKeyChar() == 'f' || e.getKeyChar() == 'F'){
draw++;
repaint();
}
}
}
So before anything else, this...
public void paintComponent(Graphics g){
if(test == true){
sp = new SecondPanel();
removeAll();
revalidate();
setContentPane(sp);
}
}
This incredibly bad! First, you are breaking the paint chain (not calling super.paintComponent) and secondly, you are changing the state of the component from within the paint cycle, this will trigger a new repaint request and will call your paintComponent again and again and again and again ....
Painting is for painting the current state of the component, nothing more. NEVER change the state of any component from within ANY paint method EVER
Instead of trying to use remove/add, consider using a CardLayout instead, see How to Use CardLayout. This will allow you to switch between the first and second panels based on your needs, from a centralised control point.
KeyListener is a fickle mistress, it wants all the attention, all of the time. It will only raise key events if the component it is registered to is focusable AND has focus. A better solution is to use the key bindings API, which has been designed to overcome this limitation and provide you with a level of control over the level of focus required to trigger the associated actions.
See How to Use Key Bindings for more details
To swap content of a container, be it a JFrame's contentPane or any JPanel, consider using a CardLayout since this tool was built specifically for this job.
Note that this code:
sp = new SecondPanel();
removeAll();
revalidate();
setContentPane(sp);
should never be found inside of a paintComponent method. This method is not under our direct control, and should be for painting and painting only. Also by not calling the super's method, you have broken the painting chain.
Also, instead of KeyListeners, use Key Bindings, and your functionality should work.
For instance, please have a look at the similar CardLayout code I created today for another similar question.
I took two open source games to learn how to overlay text onto one of the games from the other. however, whenever i try to transition one piece of code from the next all i get is exceptions. to make sure im drawing a string correct im using :
import java.awt.*;
public class charge{
Image buffer;
Graphics bufferg;
public void draw2(Graphics g2d){
g2d.setFont(new Font("Helvetica", Font.PLAIN, 13));
g2d.drawString("Most relationships seem so transitory", 20, 30);
}
}
can anyone tell me how im using graphics wrong?
Using the graphics class correctly is very tricky, especially if you're new to java. It's likely that the error your getting is a null pointer, because your g2d arg is probably null. One (preferred) way to draw text in java is to subclass the JPanel class and override the paint(Graphics) method so whenever the panel is drawn, it's drawn with text. Here's an example:
public class Test1 extends JFrame {
public Test1(){
TextPanel t = new TextPanel("Here's some text!");
getContentPane().add(t, BorderLayout.CENTER);
setMinimumSize(new Dimension(500, 500));
//Various JFrame initialization stuff.
//repaint() makes sure the text is immediately visible.
repaint();
pack();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class TextPanel extends JPanel{
private String text;
public TextPanel(String t){
text = t;
}
//Called by swing whenever this or a parent component calls repaint()
#Override
public void paint(Graphics g){
g.setFont(new Font("Helvetica", Font.PLAIN, 13));
g.drawString(text, 20, 30);
}
}
public static void main(String[] args){
new Test1();
}
}
If you want to use the text for overlays then just make sure the background of the TextPanel is transparent and place it wherever you want to on the window.
I have a problem with java Xor method:
public class Okno extends JFrame {
public static void main(String[] args) {
Okno okno = new Okno();
}
Window()
{
this.setSize(300,300);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JButton button= new JButton("Circle");
button.addActionListener(
new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Graphics2D g = (Graphics2D)Window.this.getGraphics();
g.setXORMode(Color.red);
g.setStroke(new BasicStroke(10));
g.drawOval(100, 100, 100, 100);
}
});
this.add("South",button);
this.setVisible(true);
}
It paints circle after second click on button. On Graphic from Image it works fine...
If the code works the second time, odds are good you are calling the code incorrectly. For example, you may be requesting a paint callback and then improperly invalidating the screen area, which means that while the view has changed, the is no event to start the repainting routines.
On the second button click, the paint will then detect the first button click's action, which was to change what is drawn.
Swing painting has changed slightly over the years. You might be stuck with an old tutorial or text. Take a look at the latest online offerings to get a good idea of how it should be done.