Задержка обновления панели состояния с помощью координат мыши
Пожалуйста, посмотрите последний бит этого обработчика событий:
[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);
}
Видите StatusUpdate?
Это определено в моей форме следующим образом:
m_oViewerControl.StatusUpdate = p => toolStripCoordinate.Text = String.Format("{0:0.000},{1:0.000}", p.x, p.y); ;
Все отлично работает. Единственная проблема заключается в том, что дисплей фактически не обновляется, пока я не перестану двигать мышью.
Обновить:
Это из-за картины. Если я удаляю свой код, который рисует перекрестие, и ограничиваю недействительность прямоугольником, то статусстрип обновляется практически мгновенно.
Так что это потому, что экран с двойной буферизацией обновляется и нуждается в перерисовке всего thng из-за перекрестия, это своего рода дроссели. Правильно ли хранить старую точку мыши, а затем аннулировать только последние две "строки", а не аннулировать весь экран?
Тем не менее, любая задержка рендеринга в представлении приведет к нарушению отображения экрана. Я иду об этом правильно?
Я нашел это, что похоже:
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) ;
...
}
}
Но я знаю только, как использовать рабочий поток для конкретной задачи. Если бы мне нужно было использовать рабочий поток для обновления строки состояния, тогда она мне нужна в течение всей жизни приложения. Можем ли мы сделать это?
Обновить
Я знаю, что могу перенести кое-что из этого в методы для аккуратности, но вот что я имею сейчас:
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);
}
Это работает намного лучше. Мы только увеличиваем то, что требуется, когда мы перемещаемся или масштабируем окно. Считывание координат не будет обновляться при создании прямоугольника или создании линии панорамирования. Недостатком является то, что у меня сейчас нет перекрестия.
В AutoCAD вы можете рисовать прямоугольники и перетаскивать линии, а строка состояния обновляется практически мгновенно. Так что должен быть способ сделать то и другое.