Please see the last bit of this event handler:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Action<OdGePoint3d> StatusUpdate { get; set; }
protected override void OnMouseMove(MouseEventArgs e)
{
if (e.Location != _Location)
_Location = e.Location;
if (_bZoomWindowing)
{
if (!_selectionStart.IsEmpty && !_selectionEnd.IsEmpty && _selectionEnd != e.Location)
{
_selectionEnd = e.Location;
_rcRubberBand = GetSelectionRectangle();
}
}
if(_bPanWindowMode)
_RubberLineEnd = e.Location;
_pDevice.invalidate();
Invalidate();
if (_pDevice != null)
StatusUpdate?.Invoke(GetWorldCoordinates(e.Location));
base.OnMouseMove(e);
}
See the StatusUpdate?
That is defined in my form like this:
m_oViewerControl.StatusUpdate = p => toolStripCoordinate.Text = String.Format("{0:0.000},{1:0.000}", p.x, p.y); ;
It all works fine. The only issue is that the display is not actually updated until I stop moving the mouse.
Update:
It is because of the painting. If I remove my code that draws the crosshairs and restrict the invalidation to a rectangle then the statusstruip updates pretty much instantly.
So it is that, because the doublebuffered screen is updating and needs to redraw the whole thng because of the crosshairs it kind of chokes. Is it right practice to store the old mouse point and then invalidate just the last two "lines" as opposed to invalidating the whole display?
That said, any delay in rendering in the view will cause an upset to screen readout. Am I going about it right?
I found this that is similar:
https://mentaljetsam.wordpress.com/2007/08/09/updating-a-statusstrip-from-a-worker-thread/
public partial class Main : Form
{
delegate void SetStatusCallback(String text, int nPercent);
private void buttonGo_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void SetStatus(String text, int nPercent)
{
if (statusStrip1.InvokeRequired) {
SetStatusCallback d = new SetStatusCallback(SetStatus);
this.Invoke(d, new object[] { text, nPercent } );
} else {
labelStatus.Text = text;
progressStatus.Value = nPercent;
}
}
private void backgroundWorker1_DoWork(
object sender,
DoWorkEventArgs e)
{
SetStatus("Creating HTTP Request", 20) ;
...
SetStatus("Using POST method", 40) ;
...
}
}
But I only know how to use a workerthread for a specific task. If I was to use a worker thread to update the status bar then I need it alive for the life of the application. Can we do that?
Update
I know I can moved some of this into methods for neatness, but this is what I have now:
protected override void OnMouseMove(MouseEventArgs e)
{
if (e.Location != _Location)
_Location = e.Location;
if (_bZoomWindowing)
{
// Do we need to erase the old one?
if (!_rcLastRubberBand.IsEmpty)
{
using (Region r = new Region(Rectangle.Inflate(_rcLastRubberBand, 2, 2)))
{
r.Exclude(Rectangle.Inflate(_rcLastRubberBand, -2, -2));
_pDevice.invalidate(new OdGsDCRect(_rcLastRubberBand.Left-2, _rcLastRubberBand.Right+2,
_rcLastRubberBand.Top-2, _rcLastRubberBand.Bottom+2));
Invalidate(r);
}
}
// Draw the new one
if (!_selectionStart.IsEmpty && !_selectionEnd.IsEmpty && _selectionEnd != e.Location)
{
_rcLastRubberBand = _rcRubberBand;
_selectionEnd = e.Location;
_rcRubberBand = GetSelectionRectangle();
using (Region r = new Region(Rectangle.Inflate(_rcRubberBand, 2, 2)))
{
r.Exclude(Rectangle.Inflate(_rcRubberBand, -2, -2));
_pDevice.invalidate(new OdGsDCRect(_rcRubberBand.Left-2, _rcRubberBand.Right+2,
_rcRubberBand.Top-2, _rcRubberBand.Bottom+2));
Invalidate(r);
}
}
}
if (_bPanWindowMode)
{
// Do we need to erase the last rubber band line? (Rectangle already expanded by 2 pixels)
if(!_rcLastRubberBandLine.IsEmpty)
{
using (Region r = new Region(_rcLastRubberBandLine))
{
_pDevice.invalidate(new OdGsDCRect(_rcLastRubberBandLine.Left, _rcLastRubberBandLine.Right,
_rcLastRubberBandLine.Top, _rcLastRubberBandLine.Bottom));
Invalidate(r);
}
}
// Draw the new one now
_RubberLineEnd = e.Location;
_rcLastRubberBandLine = GetSelectionRectangle(_RubberLineStart, _RubberLineEnd);
_rcLastRubberBandLine.Inflate(2, 2);
using (Region r = new Region(_rcLastRubberBandLine))
{
_pDevice.invalidate(new OdGsDCRect(_rcLastRubberBandLine.Left, _rcLastRubberBandLine.Right,
_rcLastRubberBandLine.Top, _rcLastRubberBandLine.Bottom));
Invalidate(r);
}
}
/*
OdGsDCRect rcHorz;
OdGsDCRect rcVert;
if (!_LastLocation.IsEmpty)
{
rcHorz = new OdGsDCRect(_LastLocation.X-1, _LastLocation.X+1, 0, Height);
rcVert = new OdGsDCRect(0, Width, _LastLocation.Y-1, _LastLocation.Y+1);
rcHorz.normalize();
rcVert.normalize();
_pDevice.invalidate(rcHorz);
_pDevice.invalidate(rcVert);
Invalidate(Rectangle.FromLTRB(_LastLocation.X-1, 0, _LastLocation.X+1, Height));
Invalidate(Rectangle.FromLTRB(0, _LastLocation.Y-1, Width, _LastLocation.Y+1));
_LastLocation = _Location;
}
rcHorz = new OdGsDCRect(_Location.X-1, _Location.X+1, 0, Height);
rcVert = new OdGsDCRect(0, Width, _Location.Y-1, _Location.Y+1);
rcHorz.normalize();
rcVert.normalize();
_pDevice.invalidate(rcHorz);
_pDevice.invalidate(rcVert);
Invalidate(Rectangle.FromLTRB(_Location.X - 1, 0, _Location.X + 1, Height));
Invalidate(Rectangle.FromLTRB(0, _Location.Y - 1, Width, _Location.Y + 1));
*/
//_pDevice.invalidate();
//Invalidate();
if (_pDevice != null)
StatusUpdate?.Invoke(GetWorldCoordinates(e.Location));
base.OnMouseMove(e);
}
This works much better. We only invlidate what is required when we pan or zoom window. The coordinate readout will not update when the rectangle is being made or the pan line created. The down side is I do not have my cross hairs now.
In AutoCAD you can draw rectangles and drag lines and the status bar does update pretty much instantly. So there must be a way of e doing both.