Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 94 additions & 15 deletions src/ImageJCsharp.App/Form1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public partial class Form1 : Form
private readonly List<ToolStripMenuItem> _requiresActiveImageItems = new List<ToolStripMenuItem>();
private readonly List<ToolStripMenuItem> _requiresResultsItems = new List<ToolStripMenuItem>();
private const string NoImageStatusText = "No image";
private MeasurementOptions _measurementOptions = MeasurementOptions.Default;
private ImageDocument? _document;
private Bitmap? _displayBitmap;
private RectRoi? _roi;
Expand Down Expand Up @@ -66,6 +67,7 @@ private void BuildUi()
AddActiveImageItem(analyze, "&Measure", MeasureCurrentRoi, Keys.Control | Keys.M);
AddActiveImageItem(analyze, "&Histogram", ShowHistogram, shortcutKeyDisplayString: "H");
AddActiveImageItem(analyze, "Set &Scale...", SetScale);
AddItem(analyze, "Set &Measurements...", SetMeasurements);
AddResultsItem(analyze, "Export &Results...", ExportResults, Keys.Control | Keys.E);

var view = AddMenu(menu, "&View");
Expand Down Expand Up @@ -98,13 +100,7 @@ private void BuildUi()
_resultsGrid.AllowUserToAddRows = false;
_resultsGrid.ReadOnly = true;
_resultsGrid.RowHeadersVisible = false;
_resultsGrid.Columns.Add("Name", "Name");
_resultsGrid.Columns.Add("Area", "Area");
_resultsGrid.Columns.Add("Unit", "Unit");
_resultsGrid.Columns.Add("Mean", "Mean");
_resultsGrid.Columns.Add("Min", "Min");
_resultsGrid.Columns.Add("Max", "Max");
_resultsGrid.Columns.Add("StdDev", "StdDev");
ApplyMeasurementOptions();
Controls.Add(_resultsGrid);

_statusStrip.Items.Add(_statusLabel);
Expand Down Expand Up @@ -292,17 +288,100 @@ private void MeasureCurrentRoi()

var roi = _roi ?? new RectRoi(0, 0, _document.Image.Width, _document.Image.Height);
var result = Measurements.Measure(_document.Image, roi, _document.Calibration);
_resultsGrid.Rows.Add(
_document.DisplayName,
result.Area.ToString("0.###"),
_document.Calibration.Unit,
result.Mean.ToString("0.###"),
result.Min.ToString("0.###"),
result.Max.ToString("0.###"),
result.StandardDeviation.ToString("0.###"));
_resultsGrid.Rows.Add(CreateMeasurementRow(result));
UpdateCommandStates();
}

private string[] CreateMeasurementRow(MeasurementResult result)
{
var values = new List<string> { _document?.DisplayName ?? string.Empty };
if (_measurementOptions.ShowArea)
{
values.Add(result.Area.ToString("0.###"));
values.Add(_document?.Calibration.Unit ?? PixelCalibration.Identity.Unit);
}

if (_measurementOptions.ShowMean)
{
values.Add(result.Mean.ToString("0.###"));
}

if (_measurementOptions.ShowMin)
{
values.Add(result.Min.ToString("0.###"));
}

if (_measurementOptions.ShowMax)
{
values.Add(result.Max.ToString("0.###"));
}

if (_measurementOptions.ShowStandardDeviation)
{
values.Add(result.StandardDeviation.ToString("0.###"));
}

return values.ToArray();
}

private void SetMeasurements()
{
using var form = new Form
{
Text = "Set Measurements",
Width = 260,
Height = 250,
FormBorderStyle = FormBorderStyle.FixedDialog,
StartPosition = FormStartPosition.CenterParent,
MinimizeBox = false,
MaximizeBox = false
};

var list = new CheckedListBox
{
Dock = DockStyle.Top,
Height = 150,
CheckOnClick = true
};
list.Items.Add("Area", _measurementOptions.ShowArea);
list.Items.Add("Mean", _measurementOptions.ShowMean);
list.Items.Add("Min", _measurementOptions.ShowMin);
list.Items.Add("Max", _measurementOptions.ShowMax);
list.Items.Add("StdDev", _measurementOptions.ShowStandardDeviation);
form.Controls.Add(list);

var ok = new Button { Text = "OK", DialogResult = DialogResult.OK, Dock = DockStyle.Bottom };
var cancel = new Button { Text = "Cancel", DialogResult = DialogResult.Cancel, Dock = DockStyle.Bottom };
form.Controls.Add(cancel);
form.Controls.Add(ok);
form.AcceptButton = ok;
form.CancelButton = cancel;

if (form.ShowDialog(this) != DialogResult.OK)
{
return;
}

_measurementOptions = new MeasurementOptions(
list.GetItemChecked(0),
list.GetItemChecked(1),
list.GetItemChecked(2),
list.GetItemChecked(3),
list.GetItemChecked(4));
ApplyMeasurementOptions();
UpdateCommandStates();
}

private void ApplyMeasurementOptions()
{
_resultsGrid.Rows.Clear();
_resultsGrid.Columns.Clear();
foreach (var column in _measurementOptions.GetColumnNames())
{
_resultsGrid.Columns.Add(column, column);
}
}

private void SetScale()
{
if (_document is null)
Expand Down
69 changes: 69 additions & 0 deletions src/ImageJCsharp.App/MeasurementOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Collections.Generic;

namespace ImageJCsharp.App;

public sealed class MeasurementOptions
{
public MeasurementOptions(
bool showArea,
bool showMean,
bool showMin,
bool showMax,
bool showStandardDeviation)
{
ShowArea = showArea;
ShowMean = showMean;
ShowMin = showMin;
ShowMax = showMax;
ShowStandardDeviation = showStandardDeviation;
}

public static MeasurementOptions Default { get; } = new MeasurementOptions(
showArea: true,
showMean: true,
showMin: true,
showMax: true,
showStandardDeviation: true);

public bool ShowArea { get; }

public bool ShowMean { get; }

public bool ShowMin { get; }

public bool ShowMax { get; }

public bool ShowStandardDeviation { get; }

public IReadOnlyList<string> GetColumnNames()
{
var columns = new List<string> { "Name" };
if (ShowArea)
{
columns.Add("Area");
columns.Add("Unit");
}

if (ShowMean)
{
columns.Add("Mean");
}

if (ShowMin)
{
columns.Add("Min");
}

if (ShowMax)
{
columns.Add("Max");
}

if (ShowStandardDeviation)
{
columns.Add("StdDev");
}

return columns;
}
}
30 changes: 30 additions & 0 deletions tests/ImageJCsharp.App.Tests/FormStartupTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,36 @@ public void MeasureCurrentRoiUsesDocumentCalibration()
Assert.Equal("um", unit);
}

[Fact]
public void MeasureCurrentRoiUsesSelectedMeasurementOptions()
{
string[]? columns = null;
string[]? values = null;

var capturedException = RunOnStaThread(() =>
{
using var form = new Form1();
LoadTestImage(form);
SetPrivateField(form, "_measurementOptions", new MeasurementOptions(
showArea: true,
showMean: false,
showMin: false,
showMax: true,
showStandardDeviation: false));
InvokePrivateMethod(form, "ApplyMeasurementOptions");

InvokePrivateMethod(form, "MeasureCurrentRoi");

var grid = GetPrivateField<DataGridView>(form, "_resultsGrid");
columns = grid.Columns.Cast<DataGridViewColumn>().Select(column => column.Name).ToArray();
values = grid.Rows[0].Cells.Cast<DataGridViewCell>().Select(cell => Convert.ToString(cell.Value) ?? string.Empty).ToArray();
});

Assert.Null(capturedException);
Assert.Equal(new[] { "Name", "Area", "Unit", "Max" }, columns);
Assert.Equal(new[] { "close-smoke.png", "1", "pixel", "10" }, values);
}

private static Exception? RunOnStaThread(Action action)
{
Exception? capturedException = null;
Expand Down
29 changes: 29 additions & 0 deletions tests/ImageJCsharp.App.Tests/MeasurementOptionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace ImageJCsharp.App.Tests;

public sealed class MeasurementOptionsTests
{
[Fact]
public void MeasurementOptionsDefaultPreservesCurrentResultColumns()
{
var options = MeasurementOptions.Default;

Assert.Equal(
new[] { "Name", "Area", "Unit", "Mean", "Min", "Max", "StdDev" },
options.GetColumnNames());
}

[Fact]
public void MeasurementOptionsCanLimitResultColumns()
{
var options = new MeasurementOptions(
showArea: true,
showMean: false,
showMin: false,
showMax: true,
showStandardDeviation: false);

Assert.Equal(
new[] { "Name", "Area", "Unit", "Max" },
options.GetColumnNames());
}
}
Loading