Can a progress bar be used in a class outside main?
SwingWorker
is ideal for this. The example below performs a simple iteration in the background, while reporting progress and intermediate results in a window. You can pass whatever parameters you need in a suitable SwingWorker
constructor.
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DecimalFormat;
import java.util.List;
import javax.swing.*;
/** @see http://stackoverflow.com/questions/4637215 */
public class TwoRoot extends JFrame {
private static final String s = "0.000000000000000";
private JProgressBar progressBar = new JProgressBar(0, 100);
private JLabel label = new JLabel(s, JLabel.CENTER);
public TwoRoot() {
this.setLayout(new GridLayout(0, 1));
this.setTitle("√2");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(progressBar);
this.add(label);
this.setSize(161, 100);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void runCalc() {
progressBar.setIndeterminate(true);
TwoWorker task = new TwoWorker();
task.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent e) {
if ("progress".equals(e.getPropertyName())) {
progressBar.setIndeterminate(false);
progressBar.setValue((Integer) e.getNewValue());
}
}
});
task.execute();
}
private class TwoWorker extends SwingWorker<Double, Double> {
private static final int N = 5;
private final DecimalFormat df = new DecimalFormat(s);
double x = 1;
@Override
protected Double doInBackground() throws Exception {
for (int i = 1; i <= N; i++) {
x = x - (((x * x - 2) / (2 * x)));
setProgress(i * (100 / N));
publish(Double.valueOf(x));
Thread.sleep(1000); // simulate latency
}
return Double.valueOf(x);
}
@Override
protected void process(List<Double> chunks) {
for (double d : chunks) {
label.setText(df.format(d));
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
TwoRoot t = new TwoRoot();
t.runCalc();
}
});
}
}
Update progress bar from function outside the main class in Python Tkinter
You have used OOP.You could make the most of the class.I have reconstitute your code(Also,there is an error in your code):
from tkinter import ttk
import time
import tkinter as tk
class Main(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.buttonFrame = tk.Label(text="Progress Bar")
self.buttonFrame.grid(column=0,row=0)
self.progressBar = ttk.Progressbar(self, orient="horizontal", length=286,mode="determinate")
self.progressBar.grid(column = 0, row = 3, pady=10)
# this shouldn't be run() or self.run().No "()" there(Or you can use lambda if you need to pass arguments).
self.button1 = tk.Button(self.buttonFrame, text="Run Progress Bar" ,command = self.run)
self.button1.grid(column = 0, row = 0)
def run(self):
self.progressBar['maximum'] = 100
for i in range(0, 100, 25):
time.sleep(0.05)
self.progressBar["value"] = i
self.progressBar.update()
self.progressBar["value"] = 0
self.progressBar["value"] = 100
app = Main()
app.mainloop()
java - Progress Bar - Is it possible to use setProgess() of Progress Bar outside the doInBackground() method?
You state:
but when I put setProgess() inside the method of another class it tells me that I need to make that method.
This has nothing to do with SwingWorker and all to do with basic Java. No class can call another classes instance (non-static) methods without doing so on a valid instance of the class. For your code to work, the "other" method must call setProgress(...)
on an instance of the SwingWorker, and so you must pass a reference of the SwingWorker to that other class. So pass the SwingWorker (this
inside of the SwingWorker) into the other class, and then you can happily call its methods. Again, this has nothing to do with threading, Swing, or SwingWorkers, but rather is basic bread and butter Java.
Edit: since setProgress is protected and final, your SwingWorker will have to have a public method that the other class can call, and in this method the SwingWorker will need to call its own setProgress(...)
method.
e.g.,
MyWorker class
public class MyWorker extends SwingWorker<Integer, Integer> {
private OtherClass otherClass;
public MyWorker() {
otherClass = new OtherClass(this);
}
@Override
protected Integer doInBackground() throws Exception {
otherClass.otherMethod();
return null;
}
// public method that exposes setProgress
public void publicSetProgress(int prog) {
setProgress(prog);
}
}
OtherClass:
class OtherClass {
MyWorker myWorker;
public OtherClass(MyWorker myWorker) {
this.myWorker = myWorker;
}
public void otherMethod() {
for (int i = 0; i < 100; i++) {
myWorker.publicSetProgress(i);
try {
Thread.sleep(200);
} catch (InterruptedException e) {}
}
}
}
Updating the main form's progress bar from an external class?
Here's a loosely coupled approach, with the Logic() class raising a custom event instead of directly referencing the Form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Logic logic = new Logic();
logic.Progress += new Logic.ProgressDelegate(DisplayProgess);
logic.Start();
}
public void DisplayProgess(string message, int percent)
{
if (this.InvokeRequired)
{
this.Invoke(new Logic.ProgressDelegate(DisplayProgess), new Object[] { message, percent });
}
else
{
this.label1.Text = message;
this.progressBar1.Value = percent;
}
}
}
public class Logic
{
private System.Threading.Thread T = null;
public delegate void ProgressDelegate(string message, int percent);
public event ProgressDelegate Progress;
public void Start()
{
if (T == null)
{
T = new System.Threading.Thread(new System.Threading.ThreadStart(Worker));
T.Start();
}
}
private void Worker()
{
RaiseProgress("Initializing...", 0);
System.Threading.Thread.Sleep(1000); // simulated work
RaiseProgress("Loading Map...", 25);
System.Threading.Thread.Sleep(1500); // simulated work
RaiseProgress("Loading Sprites...", 50);
System.Threading.Thread.Sleep(1200); // simulated work
RaiseProgress("Loading Sound Effects...", 75);
System.Threading.Thread.Sleep(1700);
RaiseProgress("Loading Music...", 85);
System.Threading.Thread.Sleep(1100); // simulated work
RaiseProgress("Done!", 100);
}
private void RaiseProgress(string message, int percent)
{
if (Progress != null)
{
Progress(message, percent);
}
}
}
Progress bar for loading out another JFrame class
Let your top-level container have a SwingWorker
that loads it's content, as shown here, and a PropertyChangeListener
, as shown here. When doInBackground()
calls setProgress()
, the listener will see the event.
Addendum: How do we know how much time left for the GUI to be completely loaded? …in examples, the progress bar is run with random number as simulated latency.
Correct; the simulated latency represents the granularity of your loading. Displaying the fraction of total bytes loaded would be ideal, but you may have to settle for a coarser frequency. Note that models may be constructed in the background, before any components are listening. GUI components should be constructed and manipulated only on the EDT, possibly in the worker's process()
implementation.
Multi-threaded progress bar concurrency issue outside the main view controller
First, you are abusing NSUserDefaults
in horrible ways. The documentation describes it as this...
The NSUserDefaults class provides a programmatic interface for
interacting with the defaults system. The defaults system allows an
application to customize its behavior to match a user’s preferences.
For example, you can allow users to determine what units of
measurement your application displays or how often documents are
automatically saved. Applications record such preferences by assigning
values to a set of parameters in a user’s defaults database. The
parameters are referred to as defaults since they’re commonly used to
determine an application’s default state at startup or the way it acts
by default.
You are using it to store a global variable.
Furthermore, you are completely abusing the user's CPU in your loop where you continuously are checking the value in the user defaults, and clipping off a selector to the main thread. "Abuse of the CPU" doesn't even come close to describing what this code is doing.
You should use NSProgress
for reporting progress. There is a WWDC 2015 presentation dedicated exclusively to using NSProgress
.
On to your core data usage.
Unfortunately, since you intentionally redacted all of the core data code, it's impossible to say what is going wrong.
However, based on what I see, you are probably trying to use that managed object context from your app delegate (which is probably still created with the deprecated confinement policy) from a background thread, which is a cardinal sin of the highest order as far as core data is concerned.
If you want to import data as a long running operation, use a private context, and execute the operations in the background. Use NSProgress
to communicate progress to anyone wanting to listen.
EDIT
Thanks for the advice on my core data context usage. I digged into all
the contexts in my code and re-organized the contexts inside, the
conflict problem does not happen anymore. As for NSProgress , it's a
pity that the WWDC presentation focus on the feature on iOS 9 (while
my app must compact on iOS 8 devices). However, even though I use
NSProgress, I should still tell the main thread how many data the core
data (on another thread) already has, right? How does the thread on
NSProgress know the loading progress on my core data thread? –
whitney13625
You can still use NSProgress for iOS8, then only real difference is that you can't explicitly add children, but the implicit way still works, and that video explains it as well.
You really should watch the whole video and forget about the iOS9 part, except to know that you must add children implicitly instead of explicitly.
Also, this pre-iOS9 blog post should clear up any questions you have about it.
Related Topics
Can't Start Eclipse - Java Was Started But Returned Exit Code=13
How to Render a Pdf File in Android
Android Studio Gradle Project "Unable to Start the Daemon Process /Initialization of Vm"
Hadoop "Unable to Load Native-Hadoop Library For Your Platform" Warning
Run a Java Application as a Service on Linux
Concurrent Modification Exception: Adding to an Arraylist
Why Retrieving Google Directions For Android Using Kml Data Is Not Working Anymore
The Asynctask API Is Deprecated in Android 11. What Are the Alternatives
Com.Android.Build.Transform.API.Transformexception
What Is the Most Appropriate Way to Store User Settings in Android Application
Custom Fonts and Xml Layouts (Android)
How to Write to a Folder on an Sd Card in Android
Java Refuses to Start - Could Not Reserve Enough Space For Object Heap
Why Maven Uses Jdk 1.6 But My Java -Version Is 1.7
Run Java Class File from PHP Script on a Website