JAVA Draw line with swt not deleting previous lines - java

I have an application where onMouseDown starts drawing a line and the line is drawn when onMouseUp. The problem I have is that when I move my mouse the previous lines stays. How can I do it to work normally and when the line is drawn, the previous are deleted?
To get it more clear I'm posting a screanshots:
And here is my code:
public class MainClass {
private static Point fp;
private static Point lp;
public static void main(String[] args) {
// TODO Auto-generated method stub
Display d = new Display();
Shell shell = new Shell(d);
shell.setLayout(new FillLayout());
Canvas c = new Canvas(shell, SWT.NONE);
c.setSize(100, 100);
c.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
shell.open();
createPaintListener(c);
createMouseListener(c);
createMoveListener(c);
while(!shell.isDisposed()) {
if(!d.readAndDispatch()) {
d.sleep();
}
}
d.dispose();
}
private static void createMoveListener(final Canvas c) {
// TODO Auto-generated method stub
c.addMouseMoveListener(new MouseMoveListener() {
#Override
public void mouseMove(MouseEvent e) {
// TODO Auto-generated method stub
if (fp != null) {
GC gc = new GC(c);
if(lp != null) {
gc.setXORMode(true);
gc.drawLine(fp.x, fp.y, lp.x, lp.y);
lp = new Point(e.x, e.y);
gc.drawLine(fp.x, fp.y, lp.x, lp.y);
}else {
lp = new Point(e.x, e.y);
}
gc.dispose();
}
}
});
}
private static void createMouseListener(final Canvas c) {
c.addMouseListener(new MouseListener() {
#Override
public void mouseDoubleClick(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseDown(MouseEvent e) {
// TODO Auto-generated method stub
if (fp == null) {
fp = new Point(e.x, e.y);
} else {
}
}
#Override
public void mouseUp(MouseEvent e) {
// TODO Auto-generated method stub
GC gc = new GC(c);
gc.drawLine(fp.x, fp.y, e.x, e.y);
gc.dispose();
fp = null;
}
});
}
private static void createPaintListener(Canvas c) {
c.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
// TODO Auto-generated method stub
}
});
}
}

Remove all the drawing code from the mouse listeners. The drawing should only occur inside paint(). Even though you keep newing up a GC() in the mouse listeners, internally, they all point to the same memory buffer that gets output to the screen, so you're drawing a new line every time the mouse moves, on top of the old buffer. In paint(), you're getting the an empty buffer to start with.
private static void createPaintListener(Canvas c) {
c.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
e.gc.drawLine(fp.x, fp.y, lp.x, lp.y);
}
});
}

Related

question about wait-notify in java thread

Hi I'm studying the basics of java threads,
but I'd like to get some help because I don't understand the examples in the book.
https://imgur.com/a/pcdOq2n
In this example, when the user presses any key,
the yellow bar is filled with magenta and the bar's magenta is
reduced by a thread.
But the part I don't understand is if you press the key for a long time while bar is full,
the magenta of the bar does not reduce immediately when the key is released
when I checked. the fill() function was running for a certain time even when the key was released.
I want to know, why if the bar is full and the key is pressed for a long time,
the fill() function works for a certain time even when the key is released
and the bar does not reduce immediately.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class MyLabel extends JLabel {
private int barSize = 0;
private int maxBarSize;
public MyLabel(int maxBarSize) {
this.maxBarSize = maxBarSize;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.MAGENTA);
int width = (int) ( ( (double)( getWidth() ) )/maxBarSize *barSize );
if (width == 0) return;
g.fillRect(0, 0, width, this.getHeight());
}
synchronized void fill() {
if (barSize == maxBarSize) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
return;
}
}
barSize++;
repaint();
notify();
}
synchronized void consume() {
if (barSize == 0) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
return;
}
}
System.out.println("consume");
barSize--;
repaint();
notify();
}
}
class ComsumerThread extends Thread {
private MyLabel bar;
public ComsumerThread(MyLabel bar) {
this.bar = bar;
}
#Override
public void run() {
// TODO Auto-generated method stub
while(true) {
try {
sleep(100);
bar.consume();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
return;
}
}
}
}
public class TabAndThreadEx extends JFrame {
private MyLabel bar = new MyLabel(100);
public TabAndThreadEx(String title) {
super(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.setLayout(null);
bar.setBackground(Color.orange);
bar.setOpaque(true);
bar.setLocation(20, 50);
bar.setSize(300, 20);
c.add(bar);
c.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
bar.fill();
}
});
setSize(350, 200);
setVisible(true);
c.setFocusable(true);
c.requestFocus();
ComsumerThread th = new ComsumerThread(bar);
th.start();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new TabAndThreadEx("Quickly press any key to fill the bar");
}
}

how to keep foreground the same color if its been clicked

After the component has been clicked is should remain with a foreground of Color.BLUE regardless of any mouse actions in the future. How can I do this?
this is my code so far, I feel like I should be using a boolean isntance variable to tracks whether or not the component has been clicked, but not sure how to go about this problem. Help is very much appreciciated.
this is my code so far
public class IdeaMouseListener implements MouseListener {
//instance
private JComponent x;
//constructor
public IdeaMouseListener(JComponent x){
this.x =x;
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
x.setForeground(Color.BLUE);
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
x.setForeground(Color.LIGHT_GRAY);
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
x.setForeground(Color.WHITE);
}
}
Then set a flag which indicates the "clicked" state, use this to determine what should happen, for example
public class IdeaMouseListener implements MouseListener {
//instance
private JComponent x;
private boolean wasClicked = false;
//constructor
public IdeaMouseListener(JComponent x) {
this.x = x;
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
x.setForeground(Color.BLUE);
wasClicked = true;
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
if (!wasClicked) {
x.setForeground(Color.LIGHT_GRAY);
}
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
if (!wasClicked) {
x.setForeground(Color.WHITE);
}
}
}
Set a property of the listener to control the "clicked" Color of the component. Then you only change the color when it is not the clicked color.
Something like:
public class IdeaMouseListener implements MouseListener {
//instance
private Color clickedColor;
//constructor
public IdeaMouseListener(Color clickedColor){
this.clickedColor = clickedColor;
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
Component source = e.getComponent();
source.setForeground(clickedColor);
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
Component source = e.getComponent();
if (!source.getForeground.equals(clickedColor)
component.setForeground(Color.LIGHT_GRAY);
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
Component source = e.getComponent();
if (!source.getForeground.equals(clickedColor)
component.setForeground(Color.WHITE);
}
}
Note the changes to the code:
You don't need to pass in the Component as a parameter because you can get that information from the MouseEvent. So the code is more generic
Because the code is generic, the same listener can be shared by all components.
You know pass in the "clicked color". This is not necessary, but it makes the class more reusable because you can change the property of the class easily instead of hardcoding the value.

Trying to mix Swing and LWJGL

I'm right now trying to mix LWJGL and Swing so I can have Swing's GUI and LWJGLS Graphics... But it doesn't work, Thanks in advance.
Code :
/**
*
*/
public static TSudioQE TSudio;
private static final long serialVersionUID = -8495077485468477943L;
public static void main(String[] args) {
try {
TSudioQE tsudio = new TSudioQE();
} catch (LWJGLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public TSudioQE() throws LWJGLException {
setTitle("TSudio Quall Engine 1X");
JPanel p = new JPanel();
Canvas c = new Canvas();
Display.create();
Display.setParent(c);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
// set the color of the quad (R,G,B,A)
GL11.glColor3f(0.5f, 0.5f, 1.0f);
// draw quad
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2f(100, 100);
GL11.glVertex2f(100 + 200, 100);
GL11.glVertex2f(100 + 200, 100 + 200);
GL11.glVertex2f(100, 100 + 200);
GL11.glEnd();
add(p);
setSize(800, 460);
setExtendedState(JFrame.MAXIMIZED_BOTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowIconified(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
}
#Override
public void windowDeactivated(WindowEvent e) {
// TODO Auto-generated method stub
}
I get the following error:
org.lwjgl.LWJGLException: Parent.isDisplayable() must be true
at org.lwjgl.opengl.Display.createWindow(Display.java:301)
at org.lwjgl.opengl.Display.setParent(Display.java:451)
at qq.application.TSudioQE.<init>(TSudioQE.java:47)
at qq.application.TSudioQE.main(TSudioQE.java:33)
Anyone who know how to fix it? It could be nice.
Have a great day :-)
The Canvas you set as parent for your Display has to be visible:
JFrame frame = new JFrame();
Canvas canvas = new Canvas();
frame.add(canvas);
frame.setVisible(true);
try
{
Display.setParent(canvas);
Display.create();
}
catch (LWJGLException e)
{
e.printStackTrace();
}

having problems with keyListener

i am trying to make a simple reaction test in java.
when the screen turns green i press space witch is supposed to change te boolean "clicked into false and stop the loop that measures time.
in reality the key listner does nothing.
am i adding the keay listener to the right compnent( jpanel panel)?
is there any other problems?
import java.awt.Color;
import java.awt.RenderingHints.Key;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
public class mainCheck {
// //////////////////////////////////////
public static void timeKeeper() {
boolean clicked=false;
long time = 10000;
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
panel.setBackground(Color.GREEN);
while (time > 0 && !clicked) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
time--;
}
panel.setBackground(Color.gray);
long time2= 10000-time;
JLabel x = new JLabel("" +time2+"");
panel.add(x);
}
// //////////////////////////////////////
static boolean clicked;
JFrame frame;
static JPanel panel;
public mainCheck() {
frame = new JFrame();
panel = new JPanel();
clicked = false;
Handler handler = new Handler();
frame.addKeyListener(handler);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.setVisible(true);
}
// //////////////////////////////////////
public static void main(String[] args) {
mainCheck f = new mainCheck();
panel.getActionMap();
f.timeKeeper();
}
// //////////////////////////////////////
public class Handler implements KeyListener {
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
clicked = false;
System.out.println("space pressed");
}
}
}
}
do not use Thread.sleep(5000); block Event Dispatch Thread and during sleep you can lost all events to the already visible Swing GUI
use Swing Timer instead
Thread.sleep(1); could be proper delay for space enviroment, non_human, very short period attacking latency in Native OS (8-14miliseconds, depends of Native OS)
JLabel x = new JLabel("" +time2+""); and panel.add(x); in AWT/Swing isn't any notifiers that some, any, part of JComponents are removed or added, have to notify used LayoutManager (JPanel has FlowLayout in API) by using methods revalidate and repaint, e.g.
.
JLabel x = new JLabel("" +time2+"");
panel.add(x);
panel.revalidate();
panel.repaint();
Swing GUI should be created on Initial Thread
don't to use KeyListener use KeyBindings instead, otherwise you (are focus hunter) would need to set panel.seFocusable(true);
The problem is that you "e.getKeyCode()" always is "0" so
change for "e.getKeyChar()" and "(char)32"
the other problem is in that you put clicked = false and must be
"true"
And the last problem you have is in "timeKeeper()" you have to erase "boolean" because it is already declarated
Bad
public static void timeKeeper() {
boolean clicked=false
....}
Good
public static void timeKeeper() {
clicked=false
....}
This is the correct code:
import java.awt.Color;
import java.awt.event.*;
import javax.swing.*;
public class mainCheck {
// //////////////////////////////////////
public static void timeKeeper() {
clicked=false;
long time = 10000;
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
panel.setBackground(Color.GREEN);
while (time > 0 && !clicked) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
time--;
}
panel.setBackground(Color.gray);
long time2= 10000-time;
JLabel x = new JLabel("" +time2+"");
panel.add(x);
}
// //////////////////////////////////////
static boolean clicked;
JFrame frame;
static JPanel panel;
Handler handler = new Handler();
public mainCheck() {
frame = new JFrame();
panel = new JPanel();
clicked = false;
frame.addKeyListener(handler);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.setVisible(true);
}
// //////////////////////////////////////
public static void main(String[] args) {
mainCheck f = new mainCheck();
panel.getActionMap();
f.timeKeeper();
}
// //////////////////////////////////////
public class Handler implements KeyListener {
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == (char)32) {
clicked = true;
System.out.println("space pressed");
}
}
}
}
It's a really bad idea to use Thread.sleep() to decrement the time value.
Use a Timer object instead:
public void myTimer(){
Timer myTimer = new Timer(delay, new ActionListener(){
public void actionPerformed(ActionEvent e){
//Stuff to do
}
});
}
Where delay is the amount of time you delay the timer. You start the timer with myTimer.start();

Force paint a jframe?

I have been trying to work this out by myself these past few days but I just can't seem to be able to get to a solution...... how do I force paint a JFrame and everything inside it? I have a Chat programme (client/server approach), the server class and the client one are identical code-wise? But I just can't seem to make the client one show!
import java.awt.event.ActionEvent;
public class Chat extends JFrame implements Runnable, ActionListener, WindowListener{
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JTextField line;
// TCP Components
private Socket channel = null;
private JScrollPane scrollPane;
private String toBeSent="";
private final String END_CHAT_SESSION = new Character((char)0).toString();
private PrintWriter out;
private boolean channelIsStillOpen = true;
private Socket channel;
private static JTextArea chatText;
public Chat(Socket channel) {
this.channel=channel;
addWindowListener(this);
setTitle("Remote Administrator");
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
line = new JTextField();
line.setBounds(17, 207, 289, 40);
line.setColumns(10);
JButton send = new JButton("Send");
send.addActionListener(this);
send.setBounds(312, 214, 105, 25);
contentPane.setLayout(null);
scrollPane = new JScrollPane();
scrollPane.setBounds(17, 5, 399, 196);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
contentPane.add(scrollPane);
chatText = new JTextArea();
chatText.setLineWrap(true);
chatText.setEditable(false);
chatText.setEnabled(false);
scrollPane.setViewportView(chatText);
contentPane.add(line);
contentPane.add(send);
}
#Override
public void run() {
try {
channel=new Socket(address, port);
System.out.println("Chat Connection accepted");
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(channel.getInputStream()));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
out = null;
try {
out = new PrintWriter(channel.getOutputStream(),true);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String s="";
do {
// Send data
if (toBeSent.length()!= 0) {
out.println(toBeSent);
toBeSent="";
}
// Receive data
try {
if (in.ready()) {
s = in.readLine();
if ((s != null) && (s.length() != 0) && !s.equals(END_CHAT_SESSION)) {
chatText.append("INCOMING: " + s + "\n");
}
if(s.equals(END_CHAT_SESSION)){
chatText.append("Client disconnected.");
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} while(!s.equals(END_CHAT_SESSION));
channelIsStillOpen=false;
line.setEditable(false);
line.setEnabled(false);
if(channel!=null){
try {
channel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
channel=null;
}
}
#Override
public void windowActivated(WindowEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void windowClosed(WindowEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void windowClosing(WindowEvent arg0) {
if(channelIsStillOpen){
out.println(END_CHAT_SESSION);
}
dispose();
}
#Override
public void windowDeactivated(WindowEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void windowDeiconified(WindowEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void windowIconified(WindowEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void windowOpened(WindowEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent arg0) {
String s = line.getText();
if (!s.equals("")) {
chatText.append("OUTGOING: " + s + "\n");
// Send the string
toBeSent=s;
}
line.setText("");
}
}
edit: I have even edited the code so that the class being used is always the same! Nothing!
I think you are missing this at the end of your constructor:
this.setVisible(true);
also, why don't you set? setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);, why do you want to keep the application opened?

Categories