Java Painting issues - graphics

I need help with a "paint" program. I've got the GUI established, but I'm having issues with the actual drawing portion of the program. Everything I draw disappears immediately after I draw it, and I can't figure out why.
Here is what I have so far:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JPaint extends JFrame implements ActionListener, MouseListener, MouseMotionListener {
int x, y, x2, y2;
private int select = 0;
private Graphics g;
private PaintPanel DrawPanel = new PaintPanel(this);
private JPanel ButtonPanel = new JPanel();
private JTextArea Draw = new JTextArea(20,20);
private JButton jbtRed = new JButton("Red");
private JButton jbtGreen = new JButton("Green");
private JButton jbtBlue = new JButton("Blue");
private JButton jbtErase = new JButton("Eraser");
private JButton jbtClear = new JButton("Clear");
PaintPanel l=new PaintPanel(this);
public JPaint(){
super("Java Paint");
setSize(480,320);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//build draw panel
DrawPanel.setBackground(Color.WHITE);
add(DrawPanel, BorderLayout.CENTER);
DrawPanel.setVisible(true);
//build button panel
ButtonPanel.add(jbtRed);
ButtonPanel.add(jbtGreen);
ButtonPanel.add(jbtBlue);
ButtonPanel.add(jbtErase);
ButtonPanel.add(jbtClear);
add(ButtonPanel, BorderLayout.SOUTH);
ButtonPanel.setVisible(true);
jbtRed.addActionListener(this);
jbtGreen.addActionListener(this);
jbtBlue.addActionListener(this);
jbtErase.addActionListener(this);
jbtClear.addActionListener(this);
DrawPanel.addMouseMotionListener(this);
DrawPanel.addMouseListener(this);
}
public void actionPerformed(ActionEvent e){
if(e.getSource() == jbtRed){
DrawPanel.setToolTipText("Color set to 'Red'");
select = 1;
}
if(e.getSource() == jbtGreen){
DrawPanel.setToolTipText("Color set to 'Green'");
}
if(e.getSource() == jbtBlue){
DrawPanel.setToolTipText("Color set to 'Blue'");
}
if(e.getSource() == jbtErase){
DrawPanel.setToolTipText("Erase Selected");
}
if(e.getSource() == jbtClear){
DrawPanel.setToolTipText("Drawing cleared");
}
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
DrawPanel.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
}
#Override
public void mouseReleased(MouseEvent e) {
x2 = e.getX();
y2 = e.getY();
DrawPanel.repaint();
}
}
class PaintPanel extends JPanel
{
JPaint p;
PaintPanel(JPaint in){
p=in;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// clear the screen
g.setColor(Color.white);
g.setColor(Color.RED);
g.drawLine(p.x, p.y, p.x2, p.y2);
p.x2 = p.x;
p.y2 = p.y;
}
}
class Run_JPaint {
public static void main(String[] args){
JPaint P = new JPaint();
P.setVisible(true);
}
}

You would probably want to remove the following line of code:
super.paintComponent(g);
from inside your PaintPanel class. Otherwise with each draw command your GUI resets the screen.
Good Luck!

Related

gc freed xxxx objects and than freeze application

I'm trying to create simple app which contains of ten activities. Each activity look pretty much the same, it has four buttons (different color) and when one particular button is clicked it's open next activity. OnCreate method of every activity has mediaplayer that play name of that activity. After some time I see in LogCat that gc freed some objects and at that time Activity don't play any sound and buttons are disabled.
Do you have any advice or suggestions how to resole that?
Here is code of one Activity:
public class Green extends Activity {
int buttonActive = 0;
int buttonWrong = 0;
MediaPlayer player;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_green);
buttonWrong = 0;
playSound();
Button btn = (Button)findViewById(R.id.button1);
Button btn2 = (Button)findViewById(R.id.button2);
Button btn3 = (Button)findViewById(R.id.button3);
Button btn4 = (Button)findViewById(R.id.button4);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(buttonActive == 1){
playSoundCorrect();
Intent intent = new Intent(v.getContext(),Blue.class);
startActivity(intent);
}
}
});
btn2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(buttonActive == 1 && buttonWrong == 0){
buttonWrong = 1;
playSoundWrong();
}
}
});
btn3.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(buttonActive == 1 && buttonWrong == 0){
buttonWrong = 1;
playSoundWrong();
}
}
});
btn4.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(buttonActive == 1 && buttonWrong == 0){
buttonWrong = 1;
playSoundWrong();
}
}
});
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
finish();
}
private void playSound(){
MediaPlayer player = MediaPlayer.create(this, R.raw.green);
player.start();
player.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
buttonActive = 1;
}
});
}
private void playSoundWrong(){
player = MediaPlayer.create(this, R.raw.wrong2);
if(!player.isPlaying()){
player.start();
}
player.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
buttonWrong = 0;
}
});
}
private void playSoundCorrect(){
MediaPlayer player = MediaPlayer.create(this, R.raw.correct);
player.start();
player.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
}
It looks like in private void playSound you're masking the class's player property. If you say player = MediaPlayer.create then the class's player property will be set to the new MediaPlayer, and the player will be reachable so long as the class is reachable. Instead you're saying MediaPlayer player = MediaPlayer.create, which is creating a new player variable that is scoped to the playSound method - once the method terminates the player is no longer reachable and will be garbage-collected, even if the class is still reachable.

Java FX8 UI update lags

I have some signal processing data which gets fed at roughly at 50Hz. I need to update a rectangle's opacity based on the signal value in real time. I am trying to develop the UI in JavaFX 8.
For time being I am simulating the signal value using random number generator in JavaFX service in my code.
I am using Platform.runLater to update the UI, however this doesn't update values in real time, I read through similar problems encountered by others and the normal suggestion is that not to call Platform.runLater often but to batch the updates.
In my case if I batch my updates, the frequency at which the opacity changes will not be equal to the signal frequency.
Any thoughts on how to achieve this?
public class FlickerController
{
#FXML
private Rectangle leftBox;
#FXML
private Rectangle rightBox;
#FXML
private ColorPicker leftPrimary;
#FXML
private ColorPicker leftSecondary;
#FXML
private ColorPicker rightPrimary;
#FXML
private ColorPicker rightSecondary;
#FXML
private Slider leftFrequency;
#FXML
private Slider rightFrequency;
#FXML
private Button startButton;
#FXML
private Label leftfreqlabel;
#FXML
private Label rightfreqlabel;
#FXML
private Label rightBrightness;
#FXML
private Label leftBrightness;
private boolean running = false;
DoubleProperty leftopacity = new SimpleDoubleProperty(1);
DoubleProperty rightopacity = new SimpleDoubleProperty(1);
private FlickerThread ftLeft;
private FlickerThread ftRight;
public void initialize()
{
leftopacity.addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue)
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
double brightness = leftopacity.doubleValue();
leftBrightness.setText(""+brightness);
leftBox.opacityProperty().set(brightness);
}
});
}
});
rightopacity.addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue)
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
double brightness = rightopacity.doubleValue();
rightBrightness.setText(""+brightness);
rightBox.opacityProperty().set(brightness);
}
});
}
});
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event)
{
if(running)
{
synchronized(this)
{
running=false;
}
startButton.setText("Start");
}
else
{
running=true;
ftLeft = new FlickerThread((int)leftFrequency.getValue(),leftopacity);
ftRight = new FlickerThread((int)rightFrequency.getValue(), rightopacity);
try
{
ftLeft.start();
ftRight.start();
}
catch(Throwable t)
{
t.printStackTrace();
}
startButton.setText("Stop");
}
}
});
leftFrequency.valueProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue)
{
leftfreqlabel.setText(newValue.intValue()+"");
}
});
rightFrequency.valueProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue)
{
rightfreqlabel.setText(newValue.intValue()+"");
}
});
}
class FlickerThread extends Service<Void>
{
private long sleeptime;
DoubleProperty localval = new SimpleDoubleProperty(1) ;
public FlickerThread(int freq, DoubleProperty valtoBind)
{
this.sleeptime = (1/freq)*1000;
valtoBind.bind(localval);
}
#Override
protected Task <Void>createTask()
{
return new Task<Void>() {
#Override
protected Void call() throws Exception
{
while(running)
{
double val = Math.random();
System.out.println(val);
localval.setValue(val);
Thread.sleep(sleeptime);
}
return null;
}
};
}
}
}
class FlickerThread extends Thread
{
private long sleeptime;
final AtomicReference<Double> counter = new AtomicReference<>(new Double(-1.0));
private Label label;
private Rectangle myrect;
public FlickerThread(int freq, Label label,Rectangle rect)
{
this.sleeptime = (long) ((1.0/freq)*1000.0);
System.out.println("Sleep time is "+sleeptime);
this.label = label;
this.myrect = rect;
}
#Override
public void run() {
double count = 1.0 ;
while (running) {
count = Math.random();
if (counter.getAndSet(count) == -1) {
updateUI(counter, label,myrect);
try
{
Thread.sleep(sleeptime);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
private void updateUI(final AtomicReference<Double> counter,
final Label label, final Rectangle myrect) {
Platform.runLater(new Runnable() {
#Override
public void run() {
double val = counter.getAndSet(-1.0);
final String msg = String.format("Brt: %,f", val);
label.setText(msg);
myrect.opacityProperty().set(val);
}
});
}
You have a calculation error in your code.
Consider:
1/100*1000=0
But:
1.0/100*1000=10.0
i.e. you need to use floating point arithmetic, not integer arithmetic.
There are numerous other issues with your code as pointed out in my previous comment, so this answer is more of a code review and suggested approach than anything else.
You can batch updates to runLater as in James's answer to Throttling javafx gui updates. But for an update rate of 100 hertz max, it isn't going to make a lot of difference performance-wise as JavaFX generally operates on a 60 hertz pulse cycle, unless you really overload it (which you aren't really doing in your example). So the savings you get by throttling updates will be pretty minimal.
Here is a sample you can try out (it uses James's input throttling technique):
import javafx.application.*;
import javafx.beans.property.DoubleProperty;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
public class InputApp extends Application {
private final ToggleButton controlButton = new ToggleButton("Start");
private final Rectangle box = new Rectangle(100, 100, Color.BLUE);
private final Label brightness = new Label();
private final Label frequencyLabel = new Label();
private final Slider frequency = new Slider(1, 100, 10);
private InputTask task;
#Override
public void start(Stage stage) throws Exception {
// initialize bindings.
brightness.textProperty().bind(
box.opacityProperty().asString("%.2f")
);
frequencyLabel.textProperty().bind(
frequency.valueProperty().asString("%.0f")
);
frequency.valueChangingProperty().addListener((observable, oldValue, newValue) -> {
if (controlButton.isSelected()) {
controlButton.fire();
}
});
// start and stop the input task.
controlButton.selectedProperty().addListener((observable, wasSelected, isSelected) -> {
if (isSelected) {
task = new InputTask(
(int) frequency.getValue(),
box.opacityProperty()
);
Thread inputThread = new Thread(task, "input-task");
inputThread.setDaemon(true);
inputThread.start();
controlButton.setText("Stop");
} else {
if (task != null) {
task.cancel();
}
controlButton.setText("Start");
}
});
// create the layout
VBox layout = new VBox(
10,
frequency,
new HBox(5, new Label("Frequency: " ), frequencyLabel, new Label("Hz"),
controlButton,
box,
new HBox(5, new Label("Brightness: " ), brightness)
);
layout.setPadding(new Insets(10));
// display the scene
stage.setScene(new Scene(layout));
stage.show();
}
// simulates accepting random input from an input feed at a given frequency.
class InputTask extends Task<Void> {
private final DoubleProperty changeableProperty;
private final long sleeptime;
final AtomicLong counter = new AtomicLong(-1);
final Random random = new Random(42);
public InputTask(int inputFrequency, DoubleProperty changeableProperty) {
this.changeableProperty = changeableProperty;
this.sleeptime = (long) ((1.0 / inputFrequency) * 1_000);
}
#Override
protected Void call() throws InterruptedException {
long count = 0 ;
while (!Thread.interrupted()) {
count++;
double newValue = random.nextDouble(); // input simulation
if (counter.getAndSet(count) == -1) {
Platform.runLater(() -> {
changeableProperty.setValue(newValue);
counter.getAndSet(-1);
});
}
Thread.sleep(sleeptime);
}
return null;
}
}
public static void main(String[] args) {
System.out.println(1.0/100*1000);
}
}

ActionBar tabs with MapView

I've created app using SherlockActionBar tab. One with my tabs contains MapView (Google Maps v2). Currently I have problem when I change tabs (screen below):
enter link description here
Next tab should contain ListView. Sometimes context second tab loaded correctly. Also I have problem with swiping my MapView. Currently I can only swiping up and down direction. I hope that somebody help me.
My code:
myfragment.xml
<com.google.android.gms.maps.MapView
android:id="#+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true" />
TabFragment_Map.java
public class TabFragment_Map extends SherlockFragment {
MapView mapView;
GoogleMap map;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.map_fragment, container, false);
mapView = (MapView) view.findViewById(R.id.mapview);
mapView.onCreate(savedInstanceState);
map = mapView.getMap();
map.getUiSettings().setMyLocationButtonEnabled(false);
map.setMyLocationEnabled(true);
try {
MapsInitializer.initialize(this.getActivity());
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(43.1, -87.9), 10);
return view;
}
#Override
public void onResume() {
mapView.onResume();
super.onResume();
}
#Override
public void onDestroy() {
mapView.onDestroy();
super.onDestroy();
}
#Override
public void onLowMemory() {
mapView.onLowMemory();
super.onLowMemory();
}
}
MainActivity.java
public class MainActivity extends SherlockFragmentActivity {
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
String TabFragment_Cafes;
String TabFragment_Details;
//Settery & gettery używane w mechanizmie przesyłania informacji pomiędzy fragmentami
public String getTabFragment_Cafes() {
return TabFragment_Cafes;
}
public void setTabFragment_Cafes(String tabFragment_Cafes) {
TabFragment_Cafes = tabFragment_Cafes;
}
public String getTabFragment_Details() {
return TabFragment_Details;
}
public void setTabFragment_Details(String tabFragment_Details) {
TabFragment_Details = tabFragment_Details;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);
final ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.DISPLAY_SHOW_HOME);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Mapa"), TabFragment_Map.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Kawiarnie"), TabFragment_Cafes.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Szczegóły"), TabFragment_Details.class, null);
if (savedInstanceState != null)
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
#Override
protected void onSaveInstanceState(Bundle outState) {
//super.onSaveInstanceState(outState);
outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());
}
public static class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = ((SherlockFragmentActivity)activity).getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
public void onPageScrollStateChanged(int arg0) {}
public void onPageScrolled(int arg0, float arg1, int arg2) {}
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag)
mViewPager.setCurrentItem(i);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {}
public void onTabReselected(Tab tab, FragmentTransaction ft) {}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public int getCount() {
return mTabs.size();
}
}
}
You need a custom viewpager that intercepts the swipes
package com.ecs.google.maps.v2.component;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;
public class CustomViewPager extends ViewPager {
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
// When using Maps V1
// if(v instanceof MapView){
// return true;
// }
// return super.canScroll(v, checkV, dx, x, y);
// When using Maps V2
if (v.getClass().getPackage().getName().startsWith("maps.")) {
return true;
}
return super.canScroll(v, checkV, dx, x, y);
}
}
Put this in your layout :
<com.ecs.google.maps.v2.component.CustomViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/tabs"
tools:context=".MainActivity">
And the swiping gestures should work.

dialog.show() crashes my application, why?

I'm new in adroid.
I like to do things when the color reach a value. I like (for example) show the alert if r is bigger than 30, but the application go in crash. Thank for very simple answares.
public class MainActivity extends Activity {
private AlertDialog dialog;
private AlertDialog.Builder builder;
private BackgroundColors view;
public class BackgroundColors extends SurfaceView implements Runnable {
public int grand=0;
public int step=0;
private boolean flip=true;
private Thread thread;
private boolean running;
private SurfaceHolder holder;
public BackgroundColors(Context context) {
super(context);
}
Inside this loop while running is true. is impossible to show dialogs ??
public void run() {
int r = 0;
while (running){
if (holder.getSurface().isValid()){
Canvas canvas = holder.lockCanvas();
if (r > 250)
r = 0;
r += 10;
if (r>30 && flip){
flip=false;
// *********************************
dialog.show();
// *********************************
// CRASH !!
}
try {
Thread.sleep(300);
}
catch(InterruptedException e) {
e.printStackTrace();
}
canvas.drawARGB(255, r, 255, 255);
holder.unlockCanvasAndPost(canvas);
}
}
}
public void start() {
running = true;
thread = new Thread(this);
holder = this.getHolder();
thread.start();
}
public void stop() {
running = false;
boolean retry = true;
while (retry){
try {
thread.join();
retry = false;
}
catch(InterruptedException e) {
retry = true;
}
}
}
public boolean onTouchEvent(MotionEvent e){
dialog.show();
return false;
}
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld){
super.onSizeChanged(xNew, yNew, xOld, yOld);
grand = xNew;
step =grand/15;
}
}
public void onCreate(Bundle b) {
super.onCreate(b);
view = new BackgroundColors(this);
this.setContentView(view);
builder = new AlertDialog.Builder(this);
builder.setMessage("ciao");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Log.d("Basic", "It worked");
}
});
dialog = builder.create();
}
public void onPause(){
super.onPause();
view.stop();
}
public void onResume(){
super.onResume();
view.start();
}
}
you cann't show dialog in thread.you should use handler for this.create a handler in main thread and send it to your thread and instead of dialog.show() in your thread you should send message to handler and in handleMessage method of handler write dialog.show().
example:
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch(msg.what) {
case 1:
dialog.show();
break;
}}};
and send message in thread:
handler.sendEmptyMessage(1);

Drawing a line on transparent frame

I would like to build a simple highlighter program. The idea is to set an image to change the cursor so that it will look like a highlighter. And then, when we move the cursor, it will trace a line along with our movement. The requirement here is to be able to draw the line on a transparent background (not fully transparent though, just about 55%).
My progress so far is being able to draw the line, with transparent background. However, the line is also transparent. Here's my code : left click to begin drawing, right click to stop, and press space to change color.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class FreehandExample extends JFrame implements MouseListener, MouseMotionListener, KeyListener {
private int counter = 0;
private int draw = 0;
private int red[] = {58,71,231,243,255};
private int green[] = {54,224,235,109,40};
private int blue[] = {241,95,61,52,40};
private Point start, end;
private Graphics gd;
public FreehandExample()
{
setUndecorated(true);
setBackground(new Color(255,0,0));
setSize(new Dimension(300,200));
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addKeyListener(this);
addMouseListener(this);
addMouseMotionListener(this);
setOpacity(0.55f);
setVisible(true);
}
public void mousePressed(MouseEvent e) {
start = new Point(e.getX(), e.getY());
}
public void mouseClicked(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1) draw = 1;
if(e.getButton() == MouseEvent.BUTTON3) draw = 0;
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseDragged(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {
gd = this.getGraphics();
if(draw==1){
end = new Point(e.getX(), e.getY());
gd.setColor(new Color( red[counter],green[counter],blue[counter]));
gd.drawLine(start.x, start.y, end.x, end.y);
start = end;
}
}
public static void main(String []args){
new FreehandExample();
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE) {
counter++;
if(counter>4) counter=0;
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
I have tried the concept of per-pixel transparency... but the line drawing is not being drawn immediately... there is a delay before the line is drawn. However, it indeed produced the correct result e.g the line is not transparent while the frame is transparent.
Could someone please help me modify this code to meet the requirement...?
Thanks.
I've managed to solve this problem using per-pixel transparency, thanks to someone from emunewz forum :) The trick is to call paintComponent() using repaint() all the time after drawing, but the fillRect() method only need to be called just once so that our lines won't disappear.
Here is my code :
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Paint;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GradientTranslucentWindow extends JFrame implements KeyListener, MouseListener, MouseMotionListener {
private int counter = 0;
private int draw = -1;
private int red[] = {58,71,231,243,255};
private int green[] = {54,224,235,109,40};
private int blue[] = {241,95,61,52,40};
private int R = 240;
private int G = 240;
private int B = 200;
private Point start, end;
private Graphics gd;
private JPanel panel;
public GradientTranslucentWindow() {
setBackground(new Color(0,0,0,0));
setSize(new Dimension(500,500));
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
if (g instanceof Graphics2D) {
Paint p = new GradientPaint(0.0f, 0.0f, new Color(R, G, B, 0), 0.0f, getHeight(), new Color(R, G, B, 150), true);
Graphics2D g2d = (Graphics2D)g;
g2d.setPaint(p);
if(draw==-1) g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
};
setContentPane(panel);
addKeyListener(this);
addMouseListener(this);
addMouseMotionListener(this);
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
new GradientTranslucentWindow().setVisible(true);
}
public void mousePressed(MouseEvent e) { start = new Point(e.getX(), e.getY()); }
public void mouseClicked(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1) draw = 1;
if(e.getButton() == MouseEvent.BUTTON3) draw = 0;
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseDragged(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {
gd = this.getGraphics();
if(draw==1){
end = new Point(e.getX(), e.getY());
gd.setColor(new Color( red[counter],green[counter],blue[counter]));
gd.drawLine(start.x, start.y, end.x, end.y);
start = end;
panel.repaint();
System.out.println(start.x + " - " + start.y);
}
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE) {
counter++;
if ( counter > 4 ) counter = 0;
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}

Resources