I am sending a file over network using sockets. The file is received properly without any problem. But now I am using a JProgressBar to show percentage of file sent. My problem is that even when I update GUI in a separate thread, the progress bar is updated only when file is completely sent. I also tried adjusting the priority of main thread to Thread.MIN_PRIORITY but the problem still persisted.
The complete code is long so I am not posting it (I will post if someone asks). The short code for sending file and updating progress bar is
final double temp=(done/fileSize)*100; // percentage of file sent
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
try
{
jpb.setString("Completed : "+temp+" %");
jpb.setValue((int)temp); // this is executed only when 100%
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
System.out.println(temp); // only this and
bos.write(b,0,read); // this statement is executed
Problem lies in below line:
final double temp=(done/fileSize)*100; // percentage of file sent
If done and fileSize are both not double then result of done/fileSize is 0.0.
Make them double (at least one of them) to keep the decimal part of the division.
Here is a implementation that I talked about.
It's not the best design as I did it quick and dirty but this way the file transfer code is not dependent on the UI.
public class FileTransfer implements Runnable
{
double transferPercent = 0.0;
double getTransferPercent(){ return transferPercent; }
#Override
public void run()
{
while(transferingFile)
{
// Write data
// Update transferPercent
}
}
}
public class UIClass extends TimerTask
{
private FileTransfer fileTransfer;
public void createUI()
{
TimerTask myClass = this;
JButton b = new JButton("Transfer");
b.addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
fileTransfer.start();
Timer t = new Timer();
t.scheduleAtFixedRate(myClass, 0.0, 20);
}
});
}
// Update the UI here!
#Override
public void run()
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
jpb.setValue(fileTransfer.getTransferPercent());
}
});
}
}
I'd probably design this differently. I'd make the network code independent of the UI and have it just update a variable on percentage sent.
The UI would then poll this number with a timer to update the progress bar.
But your code should work. Try adding an #Override on your run function. Maybe SwingUltities.invokeLater is calling Runnable's run function instead of your own.
Related
It's my first time making GUI on java, and I have a small issue that is pretty annoying.
My code looks something like this.
private void RunButtonActionPerformed(java.awt.event.ActionEvent evt){
richText.append("Starting...");
try{ something happens here }
richText.append("Done...");
}
The problem is that when I click run button, it waits until it finishes the task and print "Starting..." and "Done..." at the same time. How do I make it print "Starting" first before and print "Done" after?
This code is executed in EDT, so any UI changes (richText.append in your case) will be repainted after it. You should execute your heavy task in new thread.
private void RunButtonActionPerformed(java.awt.event.ActionEvent evt){
richText.append("Starting...");
new Thread() {
public void run() {
try{ something happens here }
SwingUtilities.invokeLater(new Runnable() {
richText.append("Done...");
});
}
}.start();
}
Or use SwingWorker to get extra functionality such as reporting progress of task completion
I followed the tutorial for SwingWorker as suggested on the comment, and it worked! It looks something like this.
`private class Worker extends SwingWorker<Void, Void>{
protected Void doInBackground() throws Exception{
try{ things happen here }
return null;
}
#Override
protected void done(){
try{ get (); } catch (){}
}
}
And to call this, RunButtonActionPerformed just needs new Worker().execute().
I have made a basic chat application in java using eclipse. I am now starting to add extra features to it and am currently stuck on a feature that tells the user when the other person is typing, similar to whatsapp and facebook messenger.
currently i have an integer that records if the user is typing
public int typing = 0;
when it is 0 the user isn't typing when it is 1 they are (a boolean wouldn't work for some reason)
I have an action listener on the textbox that listens for a caret update and excecutes this code:
isTyping = 1;
String typing = ("t-");
client.send(typing.getBytes());
The server then relays this back to the other clients and when they recieve this message that gets sent if they are not typing it will make the someone is typing label appear.
What i would like is something to listen for when the caret is not updating to execute this code:
isTyping = 0;
String typing = ("n-");
client.send(typing.getBytes());
Is this possible or is there a way to make this work as i seem to need to listen for no carat update?
I suggest avoiding the listener and creating a thread:
The created thread checks the value of textbox and remembers the current value of the textbox in a loop. If the value hasn't changed since the last check, it means that the user is not typing. It is up to you to consider frequency of the check and maybe only a length of the value could be used for the check.
Make a single “expiration” Timer that waits a short delay, and then executes your “not typing” action. Whenever the text field’s document changes, restart the Timer, to ensure it only manages to execute when there is a lull in the user’s typing:
JTextField textField = /* ... */;
ActionListener idleSender = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
isTyping = false;
client.send("n-".getBytes(StandardCharsets.UTF_8));
}
};
int delay = 2000; // 2 seconds
final Timer sendTimer = new Timer(delay, idleSender);
sendTimer.setRepeats(false);
sendTimer.start();
textField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent event) {
sendTimer.restart();
}
#Override
public void removeUpdate(DocumentEvent event) {
sendTimer.restart();
}
#Override
public void changedUpdate(DocumentEvent event) {
sendTimer.restart();
}
});
Some notes:
It is important to use javax.swing.Timer, not java.util.Timer. The latter uses its own thread, while the former always executes its task on the AWT Event Dispatch Thread. Calling (almost) any AWT or Swing method on any thread other than the EDT is not allowed, and while violating that rule may not generate an exception, things tend to break intermittently and unpredictably.
Using typing.getBytes() without passing an charset to getBytes() may cause data corruption on the other side. It will convert bytes using the underlying system’s default charset, which may not be the same as the server’s default charset. It is a good idea to use "n-".getBytes(StandardCharsets.UTF_8) instead.
I don’t know what “a boolean wouldn’t work for some reason” actually means, but booleans work perfectly in all circumstances. If you had a problem, you will be doing yourself a service by finding out what that problem is and fixing it, rather than writing peculiar code that sidesteps the issue, only to come back to it months later and wonder why you are using 0 and 1 in place of false and true.
Performing a command while an action isn't happening isn't really possible, because it doesn't answer one crucial question - how often should it happen? Always isn't really an answer - that would require an infinite loop constantly executing, which will throttle your application as a whole.
That said, you can set up a timed delay for sending a notification that the person has stopped editing. In my mind it would count down (via thread sleep) towards 0 and refresh to a set (positive) amount whenever a key is pressed, but it could be the opposite as well (as AJ suggests in the comments).
public class NotificationSender {
private boolean isEditing;
private final Object isEditingLock;
private DelayedTurnOffThread turnOffThread;
private static final long MS_TO_OFF_NOTIFICATION = 1000;
public NotificationSender() {
isEditing = false;
isEditingLock = new Object();
turnOffThread = null;
}
private void sendEditingNotification(String newContent) {
System.out.println("Editing, new content=" + newContent);
}
private void sendStopEditingNotification() {
System.out.println("Editing stopped");
}
public boolean isEditing() {
synchronized (isEditingLock) {
return isEditing;
}
}
public void doEdit(String newContent) {
synchronized (isEditingLock) {
isEditing = true;
sendEditingNotification(newContent);
if (turnOffThread != null) {
turnOffThread.interrupt();
}
turnOffThread = new DelayedTurnOffThread();
turnOffThread.start();
}
}
private class DelayedTurnOffThread extends Thread {
#Override
public void run() {
try {
Thread.sleep(MS_TO_OFF_NOTIFICATION);
synchronized (isEditingLock) {
isEditing = false;
sendStopEditingNotification();
}
} catch (InterruptedException e) {
//Do nothing - superceded by other turnoff thread
}
}
}
//
//DEMO CODE BELOW
//
private static class NotificationDemo extends JFrame {
private NotificationSender notificationSender;
public NotificationDemo() {
notificationSender = new NotificationSender();
JTextField textField = new JTextField();
getContentPane().add(textField, BorderLayout.CENTER);
textField.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
notificationSender.doEdit(((JTextField)e.getSource()).getText() + e.getKeyChar());
}
#Override public void keyPressed(KeyEvent e) {}
#Override public void keyReleased(KeyEvent e) {}
});
pack();
setLocationRelativeTo(null);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
public static void main(String[] args) {
new NotificationDemo();
}
}
So I tried to implement a consumer - producer pattern in android the scenario is as such:
public class CameraPreview extends SurfaceView ... {
.......
public ArrayBlockingQueue<ByteBuffer> mProcessingQueue;
public CameraPreview(){
mProcessingQueue = new ArrayBlockingQueue<ByteBuffer>(10);
HandlerThread handlerThread = new HandlerThread("Image Processing Thread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(new Runnable() {
#Override
public void run() {
new ImageProcessingThread().start();
}
});
}
public void onPreviewFrame(final byte[] data, Camera camera){
.......
if(!mProcessingQueue.offer(byteBuffer)) {
byteBuffer.clear();
Log.v("IMAGE_AVOIDED", count + "");
} else {
Log.v("IMAGE_PUSHED", count + "");
}
}
public void processImage(ByteBuffer image){
.. call to opencv jni function ..
}
public class ImageProcessingThread extends Thread{
int count = 0;
#Override
public void run() {
super.run();
while(mImageProcessingRunning){
try {
ByteBuffer image = mProcessingQueue.take();
Log.v("IMAGE_TAKEN", count++ + "");
processImage(image);
image.clear();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
However when I run this code .. it never produces the IMAGE_AVOIDED log statement .. it alternates between IMAGE_TAKEN and IMAGE_PUSHED .. one frame is pushed .. and one frame processed ..
I was hoping I'd be able to constantly place frames into mProcessingQueue and when the consumer thread was ready, to take from the queue .. this way I could drop frames if the queue was full and only place the latest frames into the queue as to get closer to real time ..
I'm sure its a synchronization problem .. maybe I'm running the same two threads in one process and therefore the scheduler is hoping back and forth through tasks ?
Any ideas / pointers ??
So it turns out that the above implementation is correct .. however I was doing some calculations in the onPreviewFrame function call .. which gave the consumer thread enough time to execute the work at hand .. Thanks all !
I am new to java
I have a function runner inside PhotoPoster class (PhotoPoster class is a Jframe with lots of buttons and other GUI elements)
it contains a START button when I click on START it executes the runner function which runs an activity & thats takes a very long time
and other GUI components are not accessible unless the runner functions completes.
I want this to work in separate thread or any other solution to help me
what I currently do is
I have made a another class GuiWorker.java
public class GuiWorker extends SwingWorker<Integer, Integer>{
public GuiWorker() throws IOException {
}
protected Integer doInBackground() throws Exception {
PhotoPoster photoPoster = new PhotoPoster();
photoPoster.ruuner();
return 0;
}
protected void done() {
System.out.println("done");
}
}
PhotoPoster.java
on button click
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
// PhotoPoster photoPoster = new PhotoPoster();
//ruuner();
EventQueue.invokeLater( new Runnable() {
#Override
public void run() {
try {
new GuiWorker().execute();
} catch (IOException ex) {
Logger.getLogger(PhotoPoster.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
it gives system out done but not performing runner function activity
Please Help me to sort out this error or any other solution
It looks as though you are queuing your long running thread back onto the Event Dispatch Thread, which means that even though you are doing invokeLater it will still block the thread.
You need to use a SwingWorker.
I have two buttons and when the user click the first one it will start a thread to update the UI, and when the user click the second one the app will set a boolean variable for the first thread to not allow it to update the thread and then it will start the second one. This is my Runnable :
class MyRunnable implements Runnable {
boolean isUpdateEnabled = true;
#Override
public void run() {
// Retrieve list from Internet. takes about 10 sec to complete.
if (isUpdateEnabled) {
runOnUiThread(new Runnable() {
public void run() {
System.out.print("Update UI");
}
});
}
}
void enableUpdate(boolean enable) {
isUpdateEnabled = enable;
}
}
but since the thread will take a time to complete, if the user press the first button again can i check if the first thread is alive and then enable it to update the thread while guarantee that the code inside if (isUpdateEnabled) will execute if or what the right way to do it?
...
// on button click
if(thread.isAlive())
runnable.enableUpdate(true);
...
I suppose you will need to do two things here :
Synchnorize access to isEnableUpdate, because two different threads are accessing it.
You may want to break your code in public void run into smaller chunks, and check the isEnableUpdate variable every once in a while when you finish some logical piece of work or something like that.
Sample :
class MyRunnable implements Runnable
{
boolean isUpdateEnabled = true;
Object myUpdateLockObj = new Object();
#Override
public void run() {
// Retrieve list from Internet. takes about 10 sec to complete.
if (isUpdateEnabled) {
runOnUiThread(new Runnable() {
public void run() {
lock(myUpdateLockObj)
{
if (!isUpdateEnabled) return;
}
//do work in parts
System.out.print("Update");
lock(myUpdateLockObj)
{
if (!isUpdateEnabled) return;
}
// do work in parts
System.out.print(" UI");
}
});
}
}
void enableUpdate(boolean enable)
{
synhronized(myUpdateLockObj)
{
isUpdateEnabled = enable;
}
}
}