A newbie, please excuse the terms and explanation.
I have a program that accepts arguments which are in seconds. This in turn runs a timer that shows on the form. I want to give the user the ability to pause the timer for a set amount of time. I am having difficulty in trying to add time after the user Clicks the button as the method that runs the timer and countdown I have a method that gets the parameters of the argument.
I would like to maybe just get the parameters/arguments globally and then use them in all the different methods or threads. I am trying to do this in c# and wpf.
Code below:
public partial class MainWindow : Window
{
//int TimeOutPeriod = Int32.Parse("3600");
//private Timer timer;
System.Timers.Timer timer = new System.Timers.Timer();
public MainWindow()
{
InitializeComponent();
//timer = new Timer(1000);
timer = new System.Timers.Timer(1000);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
string[] param = Environment.GetCommandLineArgs();
int TimeOutPeriod = Int32.Parse(param[1]);
ProgressBar1.Maximum = TimeOutPeriod;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
string [] param = Environment.GetCommandLineArgs();
int TimeOutPeriod = Int32.Parse(param[1]);
int InYourFaceDisplay = Int32.Parse(param[2]);
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)(() =>
{
if (ProgressBar1.Value < TimeOutPeriod)
{
ProgressBar1.Value += 1;
RebootCDown.Content = "Machine will reboot in : " + (TimeOutPeriod - ProgressBar1.Value) + " Secs";
if ((TimeOutPeriod - ProgressBar1.Value) < InYourFaceDisplay)
{
this.Activate();
}
}
else
{
ShutDownWindows("0");
timer.Stop();
this.Close();
}
}));
}
private void SnoozeNow_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
System.Windows.Forms.NotifyIcon ni = new System.Windows.Forms.NotifyIcon();
ShowInTaskbar = false;
ni.Icon = new System.Drawing.Icon("C:\\temp\\RebootIco.ico");
ni.Visible = true;
ShowInTaskbar = false;
ni.ShowBalloonTip(5000, "Test App", "Notify icon is working! Right click to access the context menu.", System.Windows.Forms.ToolTipIcon.Info);
Task.Delay(10000);
ShowInTaskbar = true;
}
}
Related
I'm trying to load information with worker and using reportprogress to update progress bar until finshing, but the worker stop working and doesn't finish the for loop or continue after several minutes. I don't know what's the problem and I tried every post here I can find related to this problem and didn't get anything. I hope I can finally get an answer posting my problem here.
Here's the relevant code:
public class Class1
{
public BackgroundWorker unit_read_data_setting_Worker;
public Class1()
{
unit_read_data_setting_Worker = new BackgroundWorker();
unit_read_data_setting_Worker.WorkerReportsProgress = true;
unit_read_data_setting_Worker.WorkerSupportsCancellation = false;
unit_read_data_setting_Worker.DoWork += new DoWorkEventHandler(unit_read_data_setting);
unit_read_data_setting_Worker.ProgressChanged += new ProgressChangedEventHandler(_update_progress);
unit_read_data_setting_Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Completed);
}
public void unit_read_data_setting(object sender = null, DoWorkEventArgs e = null)
{
lock (FamilyTreeViewModel.Lock_ParameterList)
{
ObservableCollection<Parameter_UC_ViewModel> _internal_parameter_list =
FamilyTreeViewModel.GetInstance.ParameterList;
if (FamilyTreeViewModel.GetInstance.SelectedUnitSetting != null)
{
if (_internal_parameter_list.Count > 0)
{
for (int i = 0; i < _internal_parameter_list.Count; i++)
{
int startValue = i * 100 / _internal_parameter_list.Count;
unit_read_data_setting_Worker.ReportProgress(startValue);
// do stuff related to the index
// when progress_bar at 76 value, the loop stoppes and cotinue after a minute
}
}
}
}
}
private void _update_progress(object sender, ProgressChangedEventArgs e)
{
FamilyTreeViewModel.GetInstance.Unit_read_data_setting_progress_bar = e.ProgressPercentage;
}
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
// never gets here but there's no error
}
}
Note: This question may look like a repetition of several question posted on the forum, but I am really stuck on this problem from quite some time and I am not able to solve this issue using the solutions posted for similar questions. I have posted my code here and need help to proceed further
So, here is my issue:
I am writing a Java GUI application which loads a file before performing any processing. There is a waiting time on an average of about 10-15 seconds during which the file is parsed. After this waiting time, what I get see on the GUI is,
The parsed file in the form of individual leaves in the JTree in a Jpanel
Some header information (example: data range) in two individual JTextField
A heat map generated after parsing the data in a different JPanel on the GUI.
The program connects to R to parse the file and read the header information.
Now, I want to use swing worker to put the file reading process on a different thread so that it does not block the EDT. I am not sure how I can build my SwingWorker class so that the process is done in the background and the results for the 3 components are displayed when the process is complete. And, during this file reading process I want to display a JProgressBar.
Here is the code which does the whole process, starting from selection of the file selection menu item. This is in the main GUI method.
JScrollPane spectralFilesScrollPane;
if ((e.getSource() == OpenImagingFileButton) || (e.getSource() == loadRawSpectraMenuItem)) {
int returnVal = fcImg.showOpenDialog(GUIMain.this);
// File chooser
if (returnVal == JFileChooser.APPROVE_OPTION) {
file = fcImg.getSelectedFile();
//JTree and treenode creation
DefaultMutableTreeNode root = new DefaultMutableTreeNode(file);
rawSpectraTree = new JTree(root);
DefaultTreeModel model = (DefaultTreeModel) rawSpectraTree.getModel();
try {
// R connection
rc = new RConnection();
final String inputFileDirectory = file.getParent();
System.out.println("Current path: " + currentPath);
rc.assign("importImagingFile", currentPath.concat("/importImagingFile.R"));
rc.eval("source(importImagingFile)");
rc.assign("currentWorkingDirectory", currentPath);
rc.assign("inputFileDirectory", inputFileDirectory);
rawSpectrumObjects = rc.eval("importImagingFile(inputFileDirectory,currentWorkingDirectory)");
rc.assign("plotAverageSpectra", currentPath.concat("/plotAverageSpectra.R"));
rc.eval("source(plotAverageSpectra)");
rc.assign("rawSpectrumObjects", rawSpectrumObjects);
REXP averageSpectraObject = rc.eval("plotAverageSpectra(rawSpectrumObjects)");
rc.assign("AverageMassSpecObjectToSpectra", currentPath.concat("/AverageMassSpecObjectToSpectra.R"));
rc.eval("source(AverageMassSpecObjectToSpectra)");
rc.assign("averageSpectraObject", averageSpectraObject);
REXP averageSpectra = rc.eval("AverageMassSpecObjectToSpectra(averageSpectraObject)");
averageSpectraMatrix = averageSpectra.asDoubleMatrix();
String[] spectrumName = new String[rawSpectrumObjects.asList().size()];
for (int i = 0; i < rawSpectrumObjects.asList().size(); i++) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode("Spectrum_" + (i + 1));
model.insertNodeInto(node, root, i);
}
// Expand all the nodes of the JTree
for(int i=0;i< model.getChildCount(root);++i){
rawSpectraTree.expandRow(i);
}
DefaultMutableTreeNode firstLeaf = ((DefaultMutableTreeNode)rawSpectraTree.getModel().getRoot()).getFirstLeaf();
rawSpectraTree.setSelectionPath(new TreePath(firstLeaf.getPath()));
updateSpectralTableandChartRAW(firstLeaf);
// List the min and the max m/z of in the respective data fields
rc.assign("dataMassRange", currentPath.concat("/dataMassRange.R"));
rc.eval("source(dataMassRange)");
rc.assign("rawSpectrumObjects", rawSpectrumObjects);
REXP massRange = rc.eval("dataMassRange(rawSpectrumObjects)");
double[] massRangeValues = massRange.asDoubles();
minMzValue = (float)massRangeValues[0];
maxMzValue = (float)massRangeValues[1];
GlobalMinMz = minMzValue;
GlobalMaxMz = maxMzValue;
// Adds the range values to the jTextField
minMz.setText(Float.toString(minMzValue));
minMz.validate();
minMz.repaint();
maxMz.setText(Float.toString(maxMzValue));
maxMz.validate();
maxMz.repaint();
// Update status bar with the uploaded data details
statusLabel.setText("File name: " + file.getName() + " | " + "Total spectra: " + rawSpectrumObjects.asList().size() + " | " + "Mass range: " + GlobalMinMz + "-" + GlobalMaxMz);
// Generates a heatmap
rawIntensityMap = gim.generateIntensityMap(rawSpectrumObjects, currentPath, minMzValue, maxMzValue, Gradient.GRADIENT_Rainbow, "RAW");
rawIntensityMap.addMouseListener(this);
rawIntensityMap.addMouseMotionListener(this);
imagePanel.add(rawIntensityMap, BorderLayout.CENTER);
coordinates = new JLabel();
coordinates.setBounds(31, 31, rawIntensityMap.getWidth() - 31, rawIntensityMap.getHeight() - 31);
panelRefresh(imagePanel);
tabbedSpectralFiles.setEnabledAt(1, false);
rawSpectraTree.addTreeSelectionListener(new TreeSelectionListener() {
#Override
public void valueChanged(TreeSelectionEvent e) {
try {
DefaultMutableTreeNode selectedNode =
(DefaultMutableTreeNode) rawSpectraTree.getLastSelectedPathComponent();
int rowCount = listTableModel.getRowCount();
for (int l = 0; l < rowCount; l++) {
listTableModel.removeRow(0);
}
updateSpectralTableandChartRAW(selectedNode);
} catch (RserveException e2) {
e2.printStackTrace();
} catch (REXPMismatchException e1) {
e1.printStackTrace();
}
}
});
spectralFilesScrollPane = new JScrollPane();
spectralFilesScrollPane.setViewportView(rawSpectraTree);
spectralFilesScrollPane.setPreferredSize(rawFilesPanel.getSize());
rawFilesPanel.add(spectralFilesScrollPane);
tabbedSpectralFiles.validate();
tabbedSpectralFiles.repaint();
rawImage.setEnabled(true);
peakPickedImage.setEnabled(false);
loadPeakListMenuItem.setEnabled(true); //active now
loadPeaklistsButton.setEnabled(true); //active now
propertiesMenuItem.setEnabled(true); // active now
propertiesButton.setEnabled(true); //active now
} catch (RserveException e1) {
JOptionPane.showMessageDialog(this,
"There was an error in the R connection. Please try again!", "Error",
JOptionPane.ERROR_MESSAGE);
} catch (REXPMismatchException e1) {
JOptionPane.showMessageDialog(this,
"Operation requested is not supported by the given R object type. Please try again!", "Error",
JOptionPane.ERROR_MESSAGE);
}
// hideProgress();
}
}
I tried creating a SwingWorker class, but I am totally confused how I can get all the three outputs on the GUI, plus have a progress bar. It is not complete, but I don't know how to proceed further.
public class FileReadWorker extends SwingWorker<REXP, String>{
private static void failIfInterrupted() throws InterruptedException {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException("Interrupted while loading imaging file!");
}
}
// The file that is being read
private final File fileName;
private JTree rawSpectraTree;
private RConnection rc;
private REXP rawSpectrumObjects;
private double[][] averageSpectraMatrix;
private Path currentRelativePath = Paths.get("");
private final String currentPath = currentRelativePath.toAbsolutePath().toString();
final JProgressBar progressBar = new JProgressBar();
// public FileReadWorker(File fileName)
// {
// this.fileName = fileName;
// System.out.println("I am here");
// }
public FileReadWorker(final JProgressBar progressBar, File fileName) {
this.fileName = fileName;
addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer) evt.getNewValue());
}
}
});
progressBar.setVisible(true);
progressBar.setStringPainted(true);
progressBar.setValue(0);
setProgress(0);
}
#Override
protected REXP doInBackground() throws Exception {
System.out.println("I am here... in background");
DefaultMutableTreeNode root = new DefaultMutableTreeNode(fileName);
rawSpectraTree = new JTree(root);
DefaultTreeModel model = (DefaultTreeModel) rawSpectraTree.getModel();
rc = new RConnection();
final String inputFileDirectory = fileName.getParent();
rc.assign("importImagingFile", currentPath.concat("/importImagingFile.R"));
rc.eval("source(importImagingFile)");
rc.assign("currentWorkingDirectory", currentPath);
rc.assign("inputFileDirectory", inputFileDirectory);
rawSpectrumObjects = rc.eval("importImagingFile(inputFileDirectory,currentWorkingDirectory)");
rc.assign("plotAverageSpectra", currentPath.concat("/plotAverageSpectra.R"));
rc.eval("source(plotAverageSpectra)");
rc.assign("rawSpectrumObjects", rawSpectrumObjects);
REXP averageSpectraObject = rc.eval("plotAverageSpectra(rawSpectrumObjects)");
rc.assign("AverageMassSpecObjectToSpectra", currentPath.concat("/AverageMassSpecObjectToSpectra.R"));
rc.eval("source(AverageMassSpecObjectToSpectra)");
rc.assign("averageSpectraObject", averageSpectraObject);
REXP averageSpectra = rc.eval("AverageMassSpecObjectToSpectra(averageSpectraObject)");
averageSpectraMatrix = averageSpectra.asDoubleMatrix();
for (int i = 0; i < rawSpectrumObjects.asList().size(); i++) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode("Spectrum_" + (i + 1));
model.insertNodeInto(node, root, i);
}
// Expand all the nodes of the JTree
for(int i=0;i< model.getChildCount(root);++i){
rawSpectraTree.expandRow(i);
}
return averageSpectra;
}
#Override
public void done() {
setProgress(100);
progressBar.setValue(100);
progressBar.setStringPainted(false);
progressBar.setVisible(false);
}
}
Any help would be very much appreciated.
Background
I have a RichTextBox control I am using essentially like a console in my WinForms application. Currently my application-wide logger posts messages using delegates and one of the listeners is this RTB. The logger synchronously sends lots of short (less than 100 char) strings denoting event calls, status messages, operation results, etc.
Posting lots of these short messages to the RTB using BeginInvoke provides UI responsiveness until heavy parallel processing starts logging lots of messages and then the UI starts posting items out of order, or the text is far behind (hundreds of milliseconds). I know this because when the processing slows down or is stopped, the console keeps writing for some time afterwords.
My temporary solution was to invoke the UI synchronously and add a blocking collection buffer. Basically taking the many small items from the Logger and combining them in a stringbuilder to be posted in aggregate to the RTB. The buffer posts items as they come if the UI can keep up, but if the queue gets too high, then it aggregates them and then posts to the UI. The RTB is thus updated piece-meal and looks jumpy when lots of things are being logged.
Question
How can I run a RichTextBox control on its own UI thread to keep other buttons on the same Form responsive during frequent but small append operations? From research, I think I need to run an STA thread and call Application.Run() on it to put the RTB on its own thread, but the examples I found lacked substantive code samples and there don't seem to be any tutorials (perhaps because what I want to do is ill advised?). Also I wasn't sure if there where any pitfalls for a single Control being on its own thread relative to the rest of the Form. (ie. Any issues closing the main form or will the STA thread for the RTB just die with the form closing? Any special disposing? etc.)
This should demonstrate the issue once you add 3 Buttons and a RichTextBox to the form. What I essentially want to accomplish is factoring away the BufferedConsumer by having the RTB on its own thread. Most of this code was hacked out verbatim from my main application, so yes, it is ugly.
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
// Fields
private int m_taskCounter;
private static CancellationTokenSource m_tokenSource;
private bool m_buffered = true;
private static readonly object m_syncObject = new object();
// Properties
public IMessageConsole Application_Console { get; private set; }
public BufferedConsumer<StringBuilder, string> Buffer { get; private set; }
public Form1()
{
InitializeComponent();
m_tokenSource = new CancellationTokenSource();
Application_Console = new RichTextBox_To_IMessageConsole(richTextBox1);
Buffer =
new BufferedConsumer<StringBuilder, string>(
p_name: "Console Buffer",
p_appendBuffer: (sb, s) => sb.Append(s),
p_postBuffer: (sb) => Application_Console.Append(sb));
button1.Text = "Start Producer";
button2.Text = "Stop All";
button3.Text = "Toggle Buffering";
button1.Click += (o, e) => StartProducerTask();
button2.Click += (o, e) => CancelAllProducers();
button3.Click += (o, e) => ToggleBufferedConsumer();
}
public void StartProducerTask()
{
var Token = m_tokenSource.Token;
Task
.Factory.StartNew(() =>
{
var ThreadID = Interlocked.Increment(ref m_taskCounter);
StringBuilder sb = new StringBuilder();
var Count = 0;
while (!Token.IsCancellationRequested)
{
Count++;
sb.Clear();
sb
.Append("ThreadID = ")
.Append(ThreadID.ToString("000"))
.Append(", Count = ")
.AppendLine(Count.ToString());
if (m_buffered)
Buffer
.AppendCollection(sb.ToString()); // ToString mimicks real world Logger passing strings and not stringbuilders
else
Application_Console.Append(sb);
Sleep.For(1000);
}
}, Token);
}
public static void CancelAllProducers()
{
lock (m_syncObject)
{
m_tokenSource.Cancel();
m_tokenSource = new CancellationTokenSource();
}
}
public void ToggleBufferedConsumer()
{
m_buffered = !m_buffered;
}
}
public interface IMessageConsole
{
// Methods
void Append(StringBuilder p_message);
}
// http://stackoverflow.com/a/5706085/1718702
public class RichTextBox_To_IMessageConsole : IMessageConsole
{
// Constants
private const int WM_USER = 0x400;
private const int WM_SETREDRAW = 0x000B;
private const int EM_GETEVENTMASK = WM_USER + 59;
private const int EM_SETEVENTMASK = WM_USER + 69;
private const int EM_GETSCROLLPOS = WM_USER + 221;
private const int EM_SETSCROLLPOS = WM_USER + 222;
//Imports
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);
// Fields
private RichTextBox m_richTextBox;
private bool m_attachToBottom;
private Point m_scrollPoint;
private bool m_painting;
private IntPtr m_eventMask;
private int m_suspendIndex = 0;
private int m_suspendLength = 0;
public RichTextBox_To_IMessageConsole(RichTextBox p_richTextBox)
{
m_richTextBox = p_richTextBox;
var h = m_richTextBox.Handle;
m_painting = true;
m_richTextBox.DoubleClick += RichTextBox_DoubleClick;
m_richTextBox.MouseWheel += RichTextBox_MouseWheel;
}
// Methods
public void SuspendPainting()
{
if (m_painting)
{
m_suspendIndex = m_richTextBox.SelectionStart;
m_suspendLength = m_richTextBox.SelectionLength;
SendMessage(m_richTextBox.Handle, EM_GETSCROLLPOS, 0, ref m_scrollPoint);
SendMessage(m_richTextBox.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
m_eventMask = SendMessage(m_richTextBox.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
m_painting = false;
}
}
public void ResumePainting()
{
if (!m_painting)
{
m_richTextBox.Select(m_suspendIndex, m_suspendLength);
SendMessage(m_richTextBox.Handle, EM_SETSCROLLPOS, 0, ref m_scrollPoint);
SendMessage(m_richTextBox.Handle, EM_SETEVENTMASK, 0, m_eventMask);
SendMessage(m_richTextBox.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
m_painting = true;
m_richTextBox.Invalidate();
}
}
public void Append(StringBuilder p_message)
{
var WatchDogTimer = Stopwatch.StartNew();
var MinimumRefreshRate = 2000;
m_richTextBox
.Invoke((Action)delegate
{
// Last resort cleanup
if (WatchDogTimer.ElapsedMilliseconds > MinimumRefreshRate)
{
// m_richTextBox.Clear(); // Real-world behaviour
// Sample App behaviour
Form1.CancelAllProducers();
}
// Stop Drawing to prevent flickering during append and
// allow Double-Click events to register properly
this.SuspendPainting();
m_richTextBox.SelectionStart = m_richTextBox.TextLength;
m_richTextBox.SelectedText = p_message.ToString();
// Cap out Max Lines and cut back down to improve responsiveness
if (m_richTextBox.Lines.Length > 4000)
{
var NewSet = new string[1000];
Array.Copy(m_richTextBox.Lines, 1000, NewSet, 0, 1000);
m_richTextBox.Lines = NewSet;
m_richTextBox.SelectionStart = m_richTextBox.TextLength;
m_richTextBox.SelectedText = "\r\n";
}
this.ResumePainting();
// AutoScroll down to display newest text
if (m_attachToBottom)
{
m_richTextBox.SelectionStart = m_richTextBox.Text.Length;
m_richTextBox.ScrollToCaret();
}
});
}
// Event Handler
void RichTextBox_DoubleClick(object sender, EventArgs e)
{
// Toggle
m_attachToBottom = !m_attachToBottom;
// Scroll to Bottom
if (m_attachToBottom)
{
m_richTextBox.SelectionStart = m_richTextBox.Text.Length;
m_richTextBox.ScrollToCaret();
}
}
void RichTextBox_MouseWheel(object sender, MouseEventArgs e)
{
m_attachToBottom = false;
}
}
public class BufferedConsumer<TBuffer, TItem> : IDisposable
where TBuffer : new()
{
// Fields
private bool m_disposed = false;
private Task m_consumer;
private string m_name;
private CancellationTokenSource m_tokenSource;
private AutoResetEvent m_flushSignal;
private BlockingCollection<TItem> m_queue;
// Constructor
public BufferedConsumer(string p_name, Action<TBuffer, TItem> p_appendBuffer, Action<TBuffer> p_postBuffer)
{
m_name = p_name;
m_queue = new BlockingCollection<TItem>();
m_tokenSource = new CancellationTokenSource();
var m_token = m_tokenSource.Token;
m_flushSignal = new AutoResetEvent(false);
m_token
.Register(() => { m_flushSignal.Set(); });
// Begin Consumer Task
m_consumer = Task.Factory.StartNew(() =>
{
//Handler
// .LogExceptions(ErrorResponse.SupressRethrow, () =>
// {
// Continuously consumes entries added to the collection, blocking-wait if empty until cancelled
while (!m_token.IsCancellationRequested)
{
// Block
m_flushSignal.WaitOne();
if (m_token.IsCancellationRequested && m_queue.Count == 0)
break;
// Consume all queued items
TBuffer PostBuffer = new TBuffer();
Console.WriteLine("Queue Count = " + m_queue.Count + ", Buffering...");
for (int i = 0; i < m_queue.Count; i++)
{
TItem Item;
m_queue.TryTake(out Item);
p_appendBuffer(PostBuffer, Item);
}
// Post Buffered Items
p_postBuffer(PostBuffer);
// Signal another Buffer loop if more items were Queued during post sequence
var QueueSize = m_queue.Count;
if (QueueSize > 0)
{
Console.WriteLine("Queue Count = " + QueueSize + ", Sleeping...");
m_flushSignal.Set();
if (QueueSize > 10 && QueueSize < 100)
Sleep.For(1000, m_token); //Allow Queue to build, reducing posting overhead if requests are very frequent
}
}
//});
}, m_token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool p_disposing)
{
if (!m_disposed)
{
m_disposed = true;
if (p_disposing)
{
// Release of Managed Resources
m_tokenSource.Cancel();
m_flushSignal.Set();
m_consumer.Wait();
}
// Release of Unmanaged Resources
}
}
// Methods
public void AppendCollection(TItem p_item)
{
m_queue.Add(p_item);
m_flushSignal.Set();
}
}
public static partial class Sleep
{
public static bool For(int p_milliseconds, CancellationToken p_cancelToken = default(CancellationToken))
{
//p_milliseconds
// .MustBeEqualOrAbove(0, "p_milliseconds");
// Exit immediate if cancelled
if (p_cancelToken != default(CancellationToken))
if (p_cancelToken.IsCancellationRequested)
return true;
var SleepTimer =
new AutoResetEvent(false);
// Cancellation Callback Action
if (p_cancelToken != default(CancellationToken))
p_cancelToken
.Register(() => SleepTimer.Set());
// Block on SleepTimer
var Canceled = SleepTimer.WaitOne(p_milliseconds);
return Canceled;
}
}
}
Posting answer as per the OP's request:
You can integrate my example of a Virtualized, High-Performance, Rich, highly customizable WPF log Viewer in your existing winforms application by using the ElementHost
Full source code in the link above
I'm trying to draw an Icon over everything on the screen (TOP MOST) similar to the chathead of new Facebook messenger
I have create a service to work in the background and based on a specific condition my icon should appear on the screen (exactly like when someone sends you a message on facebook the messenger service will hook the message and shows the chathead on the screen to notify you about the new message)
What I did:
I have created the service and gave it the permission to show system alert windows (since the head is actually a system alert window)
[assembly: UsesPermission(Name = Android.Manifest.Permission.SystemAlertWindow)]
I have inherited a class (StickyHeadView) from ImageView and implemented OnTouchListener listener using the following way :
class StickyHeadView : ImageView, Android.Views.View.IOnTouchListener
{
private StickyHeadService OwnerService;
public StickyHeadView(StickyHeadService ContextService, Context context)
: base(context)
{
OwnerService = ContextService;
SetOnTouchListener(this);
}
float TouchMoveX;
float TouchMoveY;
public bool OnTouch(View v, MotionEvent e)
{
var windowService = OwnerService.GetSystemService(Android.Content.Context.WindowService);
var windowManager = windowService.JavaCast<Android.Views.IWindowManager>();
switch (e.Action & e.ActionMasked)
{
case MotionEventActions.Move:
TouchMoveX = (int)e.GetX();
TouchMoveY = (int)e.GetY();
OwnerService.LOParams.X = (int)(TouchMoveX);
OwnerService.LOParams.Y = (int)(TouchMoveY);
windowManager.UpdateViewLayout(this, OwnerService.LOParams);
Log.Debug("Point : ", "X: " + Convert.ToString(OwnerService.LOParams.X) + " Y: " + Convert.ToString(OwnerService.LOParams.Y));
return true;
case MotionEventActions.Down:
return true;
case MotionEventActions.Up:
return true;
}
return false;
}
}
The service has wiindow manager to show the Icon on it...in Service "OnStart" event I initialize the Head :
private StickyHeadView MyHead;
public Android.Views.WindowManagerLayoutParams LOParams;
public override void OnStart(Android.Content.Intent intent, int startId)
{
base.OnStart(intent, startId);
var windowService = this.GetSystemService(Android.Content.Context.WindowService);
var windowManager = windowService.JavaCast<Android.Views.IWindowManager>();
MyHead = new StickyHeadView(this, this);
MyHead.SetImageResource(Resource.Drawable.Icon);
LOParams = new Android.Views.WindowManagerLayoutParams(Android.Views.WindowManagerLayoutParams.WrapContent,
Android.Views.WindowManagerLayoutParams.WrapContent,
Android.Views.WindowManagerTypes.Phone,
Android.Views.WindowManagerFlags.NotFocusable,
Android.Graphics.Format.Translucent);
LOParams.Gravity = GravityFlags.Top | GravityFlags.Left;
LOParams.X = 10;
LOParams.Y = 10;
windowManager.AddView(MyHead, LOParams);
}
as you can see I have declared a WindowManager and added the view (MyHead) to it with special parameters
My Problem :
When ever I try to move the View (My head) it doesn't move in a stable way and keeps having a quake!
I'm testing it using android 4.0.4 on real HTC Phone
I'm using monodroid
Please help...if the implementation of the touch is not right please suggest a better way...thank you.
In your code just use...
TYPE_SYSTEM_ALERT
or
TYPE_PHONE
instead of
TYPE_SYSTEM_OVERLAY
Hope this will help you.
a working example:
#Override
public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
chatHead = new ImageView(this);
chatHead.setImageResource(R.drawable.ic_launcher);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, //TYPE_PHONE
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
params.x = 0;
params.y = 100;
windowManager.addView(chatHead, params);
chatHead.setOnTouchListener(new View.OnTouchListener() {
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
#Override public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
initialX = params.x;
initialY = params.y;
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
return true;
case MotionEvent.ACTION_UP:
return true;
case MotionEvent.ACTION_MOVE:
params.x = initialX + (int) (event.getRawX() - initialTouchX);
params.y = initialY + (int) (event.getRawY() - initialTouchY);
windowManager.updateViewLayout(chatHead, params);
return true;
}
return false;
}
});
}
The e.GetX()/eGetY() you are using is relative to view position so when you move the view with UpdateViewLayout the next values will be relative to the move. It works using GetRawX()/GetRawY(), but you have to keep track of the initial Down rawX and rawY also.
Here is my JAVA that works:
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
layoutParams.x = Math.round(event.getRawX() - downX);
layoutParams.y = Math.round(event.getRawY() - downY);
windowManager.updateViewLayout(floatingView, layoutParams);
return true;
case MotionEvent.ACTION_DOWN:
downX = event.getRawX() - layoutParams.x;
downY = event.getRawY() - layoutParams.y;
return true;
case MotionEvent.ACTION_UP:
return true;
}
return false;
}
One comment, there's a big downside in using windowManager.updateViewLayout(...) this method will call onLayout on the floating view for each move, and that might be a performance issue, anyway until now I haven't found another method to move the floating view.
Try this might be help ful
first add global variable on your activity:
WindowManager wm;
LinearLayout lay;
float downX,downY;
after put in code to oncreate on your activity
Button btnstart=(Button)findViewById(R.id.button1);
Button btnstop=(Button)findViewById(R.id.button2);
btnstart.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(lay==null)
{
wm = (WindowManager) getApplicationContext().getSystemService(
Context.WINDOW_SERVICE);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
| WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.x = (int) wm.getDefaultDisplay().getWidth();
params.y = 0;
// params.height = wm.getDefaultDisplay().getHeight()/2;
params.width = LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
params.gravity = Gravity.TOP | Gravity.LEFT;
params.setTitle("Info");
lay = null;
lay = new LinearLayout(getApplicationContext());
lay.setOrientation(LinearLayout.VERTICAL);
// lay.setAlpha(0.5f);
TextView txt_no = new TextView(getApplicationContext());
txt_no.setTextSize(10.0f);
txt_no.setText("Moving view by stack user!");
txt_no.setTextColor(Color.BLACK);
// txt_no.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
// LayoutParams.WRAP_CONTENT));
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(0, 0, 0, 0); // margins as you wish
txt_no.setGravity(Gravity.RIGHT);
txt_no.setBackgroundColor(Color.WHITE);
txt_no.setLayoutParams(layoutParams);
txt_no.setPadding(10, 10, 10, 10);
lay.addView(txt_no);
AlphaAnimation alpha = new AlphaAnimation(0.5F, 0.5F);
alpha.setDuration(0); // Make animation instant
alpha.setFillAfter(true); // Tell it to persist after the animation ends
// And then on your layout
wm.addView(lay, params);
txt_no.startAnimation(alpha);
downX=params.x;
downY=params.y;
Log.v("MSES>", "x="+ downX +",y="+ downY);
lay.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
params.x = Math.round(event.getRawX() - downX);
params.y = Math.round(event.getRawY() - downY);
wm.updateViewLayout(lay, params);
Log.v("MSES EVENT>", "x="+ event.getRawX() +",y="+ event.getRawY());
Log.v("MSES MOVE>", "x="+ params.x +",y="+ params.y);
return true;
case MotionEvent.ACTION_DOWN:
downX = event.getRawX() - params.x;
downY = event.getRawY() - params.y;
Log.v("MSES DOWN>", "x="+ params.x +",y="+ params.y);
return true;
case MotionEvent.ACTION_UP:
//params.x = Math.round(event.getRawX() - downX);
//params.y = Math.round(event.getRawY() - downY);
//wm.updateViewLayout(lay, params);
return true;
}
return false;
}
});
}
}
});
btnstop.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (lay != null) {
lay.removeAllViews();
wm.removeViewImmediate(lay);
lay = null;
}
}
});
I want to make the clock application where user enters the number in the textbox and click ok then user get the number at every 1 sec.
Example if user enter 5 then the timer start the display screen shows the number 1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,...so on.
Now i had taken form and text field for user to enter the number,then a timer which will change the number at every second.and 10 images of number (0-9).As i want to dispaly the number in very large size.Now i had implement this logic in below way:-
public class Clock extends MIDlet implements CommandListener {
public Command GO, Exit;
TextField TxtData;
protected Display display;
int number, counter;
Form form;
private Timer timer;
private TestTimerTask task;
boolean increment, time;
private StringItem s1 = new StringItem("", "");
Image image0;
Image image1;
Image image2;
Image image3;
Image image4;
Image image5;
Image image6;
Image image7;
Image image8;
Image image9;
Image[] secondAnimation;
protected void startApp() {
display = Display.getDisplay(this);
increment = true;
time = false;
form = new Form("Clock");
TxtData = new TextField("Number:-", "", 5, TextField.NUMERIC);
try {
image0 = Image.createImage("/images/0.png");
image1 = Image.createImage("/images/1.png");
image2 = Image.createImage("/images/2.png");
image3 = Image.createImage("/images/3.png");
image4 = Image.createImage("/images/4.png");
image5 = Image.createImage("/images/5.png");
image6 = Image.createImage("/images/6.png");
image7 = Image.createImage("/images/7.png");
image8 = Image.createImage("/images/8.png");
image9 = Image.createImage("/images/9.png");
secondAnimation = new Image[]{image0,image1,image2, image3, image4, image5, image6, image7, image8, image9};
} catch (IOException ex) {
System.out.println("exception");
}
GO = new Command("Go", Command.OK, 1);
Exit = new Command("Exit", Command.EXIT, 2);
form.append(TxtData);
form.append(s1);
form.addCommand(GO);
form.addCommand(Exit);
form.setCommandListener(this);
display.setCurrent(form);
}
protected void pauseApp() {
}
protected void destroyApp(boolean unconditional) {
timer.cancel();
notifyDestroyed();
}
public void commandAction(Command cmnd, Displayable dsplbl) {
String label = cmnd.getLabel();
if (label.equals("Go")) {
try {
System.out.println("txt==" + (TxtData.getString()));
if (!TxtData.getString().equalsIgnoreCase("")) {
counter = Integer.parseInt(TxtData.getString());
if (time) {
timer.cancel();
task.cancel();
}
number = 1;
timer = new Timer();
task = new TestTimerTask();
timer.schedule(task, 1000, 1000);
}
} catch (NumberFormatException ex) {
System.out.println("exception");
}
} else if (label.equals("Exit")) {
destroyApp(true);
}
}
private class TestTimerTask extends TimerTask {
public final void run() {
time = true;
s1.setText(""+ number);
if (counter < 10) {
form.append(secondAnimation[0]);
form.append(secondAnimation[0]);
form.append(secondAnimation[number]);
} else if (counter < 100) {
form.append(secondAnimation[0]);
form.append(secondAnimation[(number % 100) / 10]);
form.append(secondAnimation[(number % 10)]);
} else if (counter < 1000) {
form.append(secondAnimation[(number % 10)]);
form.append(secondAnimation[(number % 100) / 10]);
form.append(secondAnimation[(number / 100)]);
}
number++;
if (number == counter + 1) {
number = 0;
}
}
} }
But as the form goes on appending the image as timer moves it is not showing the desired output!
I had tried to do it through LWUIT but as i had user 10 .png files and adding LWUIT.jar file make the size of .jar file 557kb which is very heavy.
So i want to do it through normal forms only.
I cant use canvas as the keypad can vary like (touch,qwerty etc).So i need to do normal form or LWUIT only.Can anyone please help me for this.
I noticed you only append items but never remove - is that intended?
Also, did you try two different forms to animate instead of one? For simple test, say, fill them in parallel, just call setCurrent for one that is not displayed in the moment of update
//...
private void appendTwice(Image image) {
form1.append(image);
form2.append(image);
}
//...
public final void run() {
time = true;
s1.setText(""+ number);
if (counter < 10) {
appendTwice(secondAnimation[0]);
//...
}
display.setCurrent(number & 1 == 0 ? form1 : form2);
number++;
//...
}
//...