JTextPane liveness - swing

My Swing application prints lines of text to a JTextPane inside of a JScrollPane when a JButton is pressed. For quick operations there is no issue. However, some JButtons invoke operations that may take a few minutes. The button remains greyed out during this time.
What currently happens is that the text is "batched up" and then I get hundreds of lines all at once at the end of the operation at the same moment the button becomes un-greyed. The problem is that I would like the text being appended to the document displayed in the JTextPane to appear sooner (at the moment it is appended) rather than at the time the entire operation completes. This would create a better user experience.
What am I doing wrong?

Use a SwingWorker for performing your background operation.
// Your button handler
public void actionPerformed(ActionEvent e) {
(new SwingWorker<Void, String>() {
public Void doInBackground() {
// perform your operation
// invoke publish("your string");
}
protected void process(List<String> chunks) {
// append your string to the scroll pane
}
}).execute();
}

You are invoking code directly from within the AWT-Thread which blocks every event. The solution is to put your long-running code in a separate Thread. As your code is executed and obtains results, you notifiy your view (using the observer/observable pattern).As your view is notified, you update the scrollpane content.
You must also verify if you are running in the AWT-Thread or not (SwingUtilities.isEventDispatchThread()). If you are not, then you need to dispatch the update of the view in the AWT-Thread using SwingUtilities.invokeLater() because Swing is not Thread-safe.

Related

LWJGL Game loop pauses whenever the GLFW window head is clicked

I have a very simple game loop.
public void gameLoop() {
long now;
long updateTime;
long wait;
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
while (!window.shouldClose()) {
now = System.nanoTime();
update();
render();
frame++;
updateTime = System.nanoTime() - now;
wait = (OPTIMAL_TIME - updateTime) / 1000000;
try {
Thread.sleep(wait);
} catch (Exception e) {
}
}
glfwTerminate();
}
Whenever I click the head of the window (the bar where the close and minimize buttons are), the loop for some reason pauses. The sounds in game continue to play (I use AL10), so this causes music and sounds to get out of sync with the game. I want to pause the window whenever this happens.
I but looking through the GLFW callbacks, there doesn't seem to be one which fixes this. The focus callback only works if I click outside of the window, and the windowPos callback only works whenever the window is moved, NOT when you simply click and hold the window head.
Is there a way to fix this problem.
This is actually expected behaviour on some platforms like Windows, where effectively glfwPollEvents will block inside of a Win32 API call for as long as you hold down the mouse button and/or potentially drag/move the window around.
In order to fix this, you should make your game loop independent of the window event processing loop, by using separate threads.
The main thread must be the one that is doing the window event processing (glfwPollEvents or glfwWaitEvents) to stay consistent with the requirements of some other platforms like macOS where this is a requirement, while another thread can do the game update and rendering.

MediaCapture and Window VisibilityChanged

[Question]
On Windows Phone 8.1, what exactly happens in between the time when the user leaves the app and the OnSuspended event fires? I'm having trouble with the ability to manage objects in that span, in particular MediaCpture object.
To better explain the problem, here is the scenario:
The user is on a page with a video preview being pumped to a CaptureElement
The user taps the Start button
The user taps Back button and returns to the page with a broken MediaCapture
With WinRT there isn't an ObscuredEvent and OnNavigatingFrom doesn’t fire unless you’re going to another page in the same Frame. After some investigation, I've found that the only event that fires is Window.Current.VisibilityChanged
I've gone ahead and hook it when the page is NavigatedTo and unhooked in OnNavigatedFrom (see ex2 below). Inside the event, I check for parameter that tells if the app is hiding or showing and dispose/initialize accordingly(see ex.1 below).
[Problem]
However, this only works with the debugger attached. If I do this without the debugger attached, it doesn't reinitialize and frequently crashes the camera and I have to literally reboot the device.
Code Example 1 (note: e.Visible == false is leaving the app and true when returning)
async void Current_VisibilityChanged(object sender, VisibilityChangedEventArgs e)
{
if (!e.Visible) //means leaving the app
{
await DisposeAll(); //cleans the MediaCapture and CaptureElement
}
else
{
if(mediaCaptureManager != null) await DisposeAll();
await Initialization(); //set up camera again
}
}
Example 2 (hooking into the event)
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Window.Current.VisibilityChanged += Current_VisibilityChanged;
this.navigationHelper.OnNavigatedTo(e);
}
protected async override void OnNavigatedFrom(NavigationEventArgs e)
{
Window.Current.VisibilityChanged -= Current_VisibilityChanged;
this.navigationHelper.OnNavigatedFrom(e);
}
[Update: Resolution]
Instead of using VisibilityChanged, hook into Window.Current.Activated on the page's constructor. With the debugger completely detached, the Activated event will provide the WindowActivationState parameter in the WindowActivatedEventArgs. Like this:
private async void CurrentOnActivated(object sender, WindowActivatedEventArgs e)
{
if(e.WindowActivationState == CoreWindowActivationState.Deactivated)
{
//dispose MediaCapture here
}
else if(e.WindowActivationState == CoreWindowActivationState.CodeActivated || e.WindowActivationState == CoreWindowActivationState.PointerActivated)
{
//initialize MediaCapture here
}
}
See my answer in https://stackoverflow.com/a/28592882/3998132. Using Window.VisibilityChanged in conjunction with your Page\UserControl Loaded\Unloaded handler should solve your issue I believe.
Using Window.Activated is less desirable than Window.VisibilityChanged because Activated relates to being visible AND having focus where as VisibilityChanged only pertains to visibility. For showing a preview having focus is not applicable. Since Windows Store apps on Windows Phone can only have one Window showing there is no difference in using either however if your app becomes universal and runs on let's say on Windows 8+ Modern shell (which can show multiple Store apps with the Snap window feature) or Windows 10 desktop (which can support multiple Store apps showing at the same time) you will not want to stop preview when a user changes focus from your app but your app is still showing.
I'm not sure if it wouldn't be more suitable to use Suspending/Resuming events. Note only that in this case, you will have to debug it properly - it behaves little different while being run with/without debugger attached.
As for the code - hooking your event in OnNavigatedTo/OnNavigatedFrom is not a good idea - when the OS suspends the app and you are using SuspensionManager then OnNavigatedFrom will be called, but when you go back to your app (resume it), then OnNavigatedTo will not be called.
Using Window events may also work here, but why not subscribe it once, somewhere in constructor? - it's window-wide and hence in phone there is only one window, which stands for app, then subscribe once. In this case, you may add a line that recognizes the current page in window and if that page contains mediacapture then dispose (create similar). Then you can also dispose/initialize in navigation events in case user doesn't leave your app and just navigate.

Swing JTabbedPane : addChangeListener or addContainerListener or both?

I have one swing code written by other person. For swing tabbed pane, he has added both change and container listener and both calls the same method:
addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent theEvent ) {
someMethod();
}
} );
addContainerListener(new ContainerAdapter() {
public void componentAdded(ContainerEvent theEvent) {
someMethod();
}
public void componentRemoved(ContainerEvent theEvent) {
someMethod();
}
} );
Whenever tab is removed from this tabbed pane, it internally calls JTabbedPane.removeTabAt(int index), which in turn calls fireStateChanged() causing new change event listened by change listener.
Now as new component (tab) is removed from tabbed pane, it also calls componentRemoved(ContainerEvent theEvent) method of container listener.
Both change even and container events, then calls same method someMethod(), which does set background and foreground colors.
I would like to know, if this kind code might cause some issues. Recently we are facing random IndexOutOfBoundException exeptions. I am just wondering, if this is causing this issue.
Also as per my understanding in swing, once event is listened, logic inside it should be executed using worker thread (e.g. SwingWorker). Please let me know if this is correct.
I am new to swing, thus any hint would be appreciated.
Thanks.
Whenever tab is removed from this tabbed pane, it internally calls
JTabbedPane.removeTabAt(int index), which in turn calls
fireStateChanged() causing new change event listened by change
listener.
This is true if the removed tab is also the selected tab. In the other cases, you won't be notified.
You need to choose what event you want to listen to:
Addition/Removal of components?--> go for ContainerListener
Selected tab? --> go for ChangeListener
I would like to know, if this kind code might cause some issues.
Recently we are facing random IndexOutOfBoundException exeptions. I am
just wondering, if this is causing this issue.
Since there is no line in your sample code that could throw that Exception, it is impossible to answer your question. Post an SSCCE that shows your issue.
Also as per my understanding in swing, once event is listened, logic
inside it should be executed using worker thread (e.g. SwingWorker).
Please let me know if this is correct.
It depends:
If you need to modify anything in the UI, anything related to Swing, it needs to be executed on the EDT (Event Dispatching Thread) and thus, SwingWorker is not an option.
If you need to perform business logic operations, and especially if they can be lengthy, then you should indeed use a SwingWorker or any other mechanism to execute that code in another thread than the EDT. Consider visiting the Swing tag wiki on "Concurrency"

Adding a indeterminate JProgressBar from an action listener

I want a indeterminate progress bar to pop up as soon as the user presses the "run" button and then close when the work to be done by the application is finished. I used NetBeans to develop the GUI. How should I go about it? The gui class extends JFrame. Here is the action listener for the run button:
public class GUI extends JFrame{
// other methods and constructos....
private JProgressBar pb = new JProgressBar();
private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
pb.setIndeterminate(true);
//other functions start...
runButton.setEnabled(false);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
//....blah blah
}
}
How do I add the progressbar to my JFrame, and then remove it when my work is done? I do NOT want to use Swing Worker.
You do not want to use the SwingWorker but you will have to (or a similar mechanism). You cannot show a JProgressBar while you keep the Event Dispatch Thread (EDT) occupied with your calculations.
You will have to move your calculations to a separate Thread to free the EDT. Then the EDT will be able to show a JProgressBar during the calculations, and remove it when they are finished.
More information on this can be found in the 'Concurrency in Swing' tutorial. An example of a SwingWorker and a JProgressBar can be found here.

Setting the application focus to a java-program in Ubuntu/LTSP

We are using LTSP with Thin-Clients. We are using it, to run a Java-Swing-Application. The users should not be able to do anything else, so instead of a Gnome-Session we use a shell-script to start our application.
Nearly everything works perfect but one thing: When the Thin-Client starts, the application starts too but doesn't receive the focus. We have to click once with the mouse inside the application, which is not that good, because the application is designed to be used without a mouse.
I didn't found anything useful, a toFront() on my Main Frame wasn't successful.
Has anyone any better suggestions??
You can use method java.awt.Window#setAlwaysOnTop(boolean) to grab the focus and after the first user interaction reset the alwayOnTop property.
You could try to call requestFocus on your JFrame as soon as it becomes visible:
JFrame frame = new JFrame();
frame.addComponentListener(new ComponentAdapter() {
public void componentShown(ComponentEvent e) {
((JFrame) e.getSource()).requestFocus();
}
});
frame.setVisible(true);