I need to draw a user defined number of grids using C# WPF. My code works but is overly long if the maximum allowed number of grids is large - is there a more concise way?
The following code shows how 1 grid is currently drawn on gridCanvas (a WPF Grid Control) - it is repeated for each additional grid that may be needed.
private void DrawInvGrid(int[,] initialPosn)
{
PathFigure myPathFigure1 = new PathFigure();
GeometryGroup myGeometryGroup1 = new GeometryGroup();
LineSegment myLineSegment1 = new LineSegment();
PathSegmentCollection myPathSegmentCollection1 = new PathSegmentCollection();
PathFigureCollection myPathFigureCollection1 = new PathFigureCollection();
// repeat declarations for each grid
int gridx = 5;
int gridy = 5;
int gridsize = 11;
// create grid 1
for (int z = 0; z < 5; z++)
{
int startpt_1x = (initialPosn[0, 0] - 5);
int startpt_1y = (initialPosn[0, 1] - 5);
for (int i = 0; i <= gridx; i++)
{
myPathFigure1 = new PathFigure();
myPathSegmentCollection1 = new PathSegmentCollection();
myPathFigure1.StartPoint = new System.Windows.Point(startpt_1x +
(i * gridsize), startpt_1y);
myLineSegment1 = new LineSegment();
myLineSegment1.Point = new System.Windows.Point(startpt_1x + (i * gridsize),
startpt_1y + gridy * gridsize);
myPathSegmentCollection1.Add(myLineSegment1);
myPathFigure1.Segments = myPathSegmentCollection1;
myPathFigureCollection1.Add(myPathFigure1);
xgridpos1.Add(startpt_1x + (i * gridsize));
}
for (int i = 0; i <= gridy; i++)
{
myPathFigure1 = new PathFigure();
myPathSegmentCollection1 = new PathSegmentCollection();
myPathFigure1.StartPoint = new System.Windows.Point(startpt_1x, startpt_1y +
(i * gridsize));
myLineSegment1 = new LineSegment();
myLineSegment1.Point = new System.Windows.Point(startpt_1x + gridx *
ridsize, startpt_1y + (i * gridsize));
myPathSegmentCollection1.Add(myLineSegment1);
myPathFigure1.Segments = myPathSegmentCollection1;
myPathFigureCollection1.Add(myPathFigure1);
ygridpos1.Add(startpt_1y + (i * gridsize));
}
}
// repeat grid creation loop for each grid
// display grid 1
gridCanvas.Children.Clear();
PathGeometry myPathGeometry1 = new PathGeometry();
myPathGeometry1.Figures = myPathFigureCollection1;
myPath1.Stroke = System.Windows.Media.Brushes.Green;
myPath1.StrokeThickness = 1;
myPath1.ToolTip = gridname;
myPath1.Data = myPathGeometry1;
gridCanvas.Children.Add(myPath1);
// repeat display routine for each grid
}
All grids are identical in any particular run - only the position of the grid (defined by int[,] initialPosn) varies from grid to grid. Any suggestions on more efficient alternatives appreciated.
Extract the repetitive code into a method that takes only those values that change (the position in your case) as parameters.
Related
I want to make a tiles based scrolling game in Visual Studio C# using forms. I know its not the best platform for this but those are set parameters. I suppose the easiest way to think of the end program is like pokemon 2d top down world scrolling.
I can create a 2d array of picture boxes and allocated images to them based on a text 2d array of tile ids. I can scroll the picture boxes and when they reach a certain place, jump back to the original location and display a shifted tile.
My issue is adding controls, it only adds a column rather than the full grid. I have tried using tables but with the same problem.
Has anyone done this type of large world scroller using VSC# and forms? Are there any tutorials or suggestions? Thanks.
EDIT - Code added'
public Form1()
{
InitializeComponent();
TableLayoutPanel wholescreen = new TableLayoutPanel();
wholescreen.Location = new System.Drawing.Point(0,0);
wholescreen.Size = new System.Drawing.Size(200,200);
wholescreen.RowCount = 2;
wholescreen.ColumnCount = 2;
Controls.Add(wholescreen);
PictureBox item = new PictureBox();
item.Size = new System.Drawing.Size(50, 50);
item.ImageLocation = "C:\\Users\\i.price\\Documents\\1.png";
for (int x = 0; x < 2; x++)
{
for (int y = 0; y < 2; y++)
{
item.Left = x * 50;
item.Top = y * 50;
wholescreen.Controls.Add(item,x,y);
}
}
}
'
another way i tried....'
int WIDTH = 3;
int HEIGHT = 3;
PictureBox[] grid = new PictureBox[9];
//PictureBox[,] grid = new PictureBox[3, 3];
//int[,] level1 = new int[2, 2] { { 1, 2 }, { 3, 4 } };
int playerx = 0;
public Form1()
{
InitializeComponent();
int y = 0;
int x = 0;
for (int cntr = 0; cntr < HEIGHT*WIDTH; cntr++)
{
if ((cntr % HEIGHT) == 0)
{
x++;
y = 0;
}
grid[cntr] = new PictureBox();
grid[cntr].Left = x * 50;
grid[cntr].Top = y * 50;
grid[cntr].ImageLocation = "C:\\Users\\i.price\\Documents\\1.png";
Controls.Add(grid[cntr]);
}
}
'
I think you are just creating one square and moving it around. Try...
private void Method2()
{
TableLayoutPanel wholescreen = new TableLayoutPanel();
wholescreen.BackColor = Color.AliceBlue;
wholescreen.Location = new System.Drawing.Point(0, 0);
wholescreen.Size = new System.Drawing.Size(200, 200);
wholescreen.RowCount = 2;
wholescreen.ColumnCount = 2;
Controls.Add(wholescreen);
PictureBox item;
// item.ImageLocation = "C:\\Users\\i.price\\Documents\\1.png";
for (int x = 0; x < 2; x++)
{
for (int y = 0; y < 2; y++)
{
item = new PictureBox();
item.Size = new System.Drawing.Size(50, 50);
item.BackColor = Color.Blue;
//item.Left = 0;
//item.Top = 0;
wholescreen.Controls.Add(item, x, y);
}
}
}
enter image description here
I have captured points data from bamboo slate,and converted them to Windows.UI.Input.Inking.InkStroke data.Then I put them in a InkPresenter.StrokeContainer rendered like this image above.Strokes sticked to each other,how can I seperate them?
This is my code below.
private void DataDisplay()
{
List<InkPoint> list = new List<InkPoint>();
List<InkStroke> strokes = new List<InkStroke>();
InkDrawingAttributes drawingAttributes1 = new InkDrawingAttributes();
drawingAttributes1.Color = Colors.Black;
drawingAttributes1.Size = new Size(1, 1);
InkStrokeBuilder builder = new InkStrokeBuilder();
builder.SetDefaultDrawingAttributes(drawingAttributes1);
inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes1);
inkCanvas.InkPresenter.IsInputEnabled = true;
foreach (var item in data.Stroke)
{
string[] strArray = item.Split(',');
for (int i = 9; i <= strArray.Length - 5; i += 5)
{
float x = float.Parse(strArray[i]) / 30;
float y = float.Parse(strArray[i + 1]) / 30;
float pressure = float.Parse(strArray[i + 2]) / 1000;
Point point = new Point(x, y);
InkPoint ip = new InkPoint(point, pressure);
list.Add(ip);
}
Matrix3x2 matrix3X2 = new Matrix3x2(1, 0, 0, 1, 0, 0);
InkStroke newStroke = builder.CreateStrokeFromInkPoints(list, matrix3X2);
strokes.Add(newStroke);
}
inkCanvas.InkPresenter.StrokeContainer.AddStroke(strokes);
}
I am showing multiple Y axis for chart by using below code. When any axis label value is having more than 3 digits then that axis Label/Title is getting overlap with other axis Label (as shown in image).
int leftIndex = 0, rightIndex = 0;
int relativePosition = 0;
foreach (Steema.TeeChart.Axis axis in this.tChart.Axes.Custom)
{
axis.Visible = true;
axis.PositionUnits = Steema.TeeChart.PositionUnits.Pixels;
axis.RelativePosition = 0 - (axis.OtherSide ? rightIndex++ : leftIndex++) * 60;
relativePosition = relativePosition + (axis.AxisRect().Width + 60);
}
You should be able to get your chart to render correctly by slightly modifying the constant in your calculation, e.g.
TChart _tChart;
public Form1()
{
InitializeComponent();
_tChart = new TChart();
_tChart.Dock = DockStyle.Fill;
_tChart.Series.Add(typeof(Line)).FillSampleValues();
_tChart.Series.Add(typeof(Line)).FillSampleValues();
_tChart.Series.Add(typeof(Line)).FillSampleValues();
_tChart.Series[0].YValues.Value = _tChart.Series[2].YValues.Value.Select(x => x * 100).ToArray();
_tChart.Header.Text = Utils.Version;
_tChart[0].CustomVertAxis = _tChart.Axes.Custom.Add();
_tChart[0].CustomVertAxis.Title.Text = "Axis One Title";
_tChart[0].CustomVertAxis.Title.Angle = 90;
_tChart[1].CustomVertAxis = _tChart.Axes.Custom.Add();
_tChart[1].CustomVertAxis.Title.Text = "Axis Two Title";
_tChart[1].CustomVertAxis.Title.Angle = 90;
_tChart[2].CustomVertAxis = _tChart.Axes.Custom.Add();
_tChart[2].CustomVertAxis.Title.Text = "Axis Three Title";
_tChart[2].CustomVertAxis.Title.Angle = 90;
int leftIndex = 0, rightIndex = 0;
for (int i = 0; i < this._tChart.Axes.Custom.Count; i++)
{
var axis = this._tChart.Axes.Custom[i];
axis.Visible = true;
axis.PositionUnits = Steema.TeeChart.PositionUnits.Pixels;
axis.RelativePosition = 0 - (axis.OtherSide ? rightIndex++ : leftIndex++) * (i == 1 ? 80: 70);
}
_tChart.Panel.MarginLeft = 30;
this.Controls.Add(_tChart);
}
Which here gives me:
I am looking to create a dynamic grid of picture boxes that will be generated once the user enters their desired number of rows and columns.
e.g. If user enters 3x3, 9 total picture boxes will be created in a grid like form.
Currently, my code will create all the desired picture boxes, but it will indent the first one in each new column creating an awkward shaped grid.
int rows = Convert.ToInt32(txtRow.Text);
int columns = Convert.ToInt32(txtColumn.Text);
// coordinates to place first box in the grid
int x = 211;
int y = 136;
int totalBoxes = rows * columns;
List<PictureBox> pictureBoxList = new List<PictureBox>();
for (int i = 0; i < totalBoxes; i++)
{
while (i < rows)
{
PictureBox picture = new PictureBox
{
Name = "pictureBox" + i,
Size = new Size(70, 60),
Location = new Point(x, y),
BorderStyle = BorderStyle.Fixed3D,
SizeMode = PictureBoxSizeMode.Zoom,
Visible = true
};
this.Controls.Add(picture);
pictureBoxList.Add(picture);
y = y + 59;
break;
}
while (i < columns)
{
PictureBox picture = new PictureBox
{
Name = "pictureBox" + i,
Size = new Size(70, 60),
Location = new Point(x, y),
BorderStyle = BorderStyle.Fixed3D,
SizeMode = PictureBoxSizeMode.Zoom,
Visible = true
};
this.Controls.Add(picture);
pictureBoxList.Add(picture);
x = x + 67;
break;
}
}
you can set picturebox locations like this:
PictureBox picture = new PictureBox
{
Location = new Point(i%columns * desiredWidth, i/columns * desiredHeight),
....
};
for example as picturebox size is (70,60), with a 5 pixel more space between you may like it as new Point(i%columns * 75, i/columns * 65) //desiredWidth=75, desiredHeight=65
You may also give it an start Indent too:
Location = new Point(x+ i%columns * desiredWidth,y+ i/columns * desiredHeight);
I would do it like:
int w=75, h = 65;
PictureBox picture = new PictureBox
{
Name = "pictureBox" + i,
Size = new Size(70, 60),
Location = new Point(x + i%columns * w, y + i/columns * h),
BorderStyle = BorderStyle.Fixed3D,
SizeMode = PictureBoxSizeMode.Zoom,
Visible = true
};
You can use on cycle from 0 up to total picture box numbers, as you started in your code. In this case you should calculate position of each box, as Ashkan Mobayen Khiabani show you, like this:
// size of the boxes
Size size = new Size(70, 60);
int totalBoxes = rows * columns;
List<PictureBox> pictureBoxList = new List<PictureBox>();
for (int i = 0; i < totalBoxes; i++)
{
int curentColumn = i % columns;
int currentRow = i / columns;
int curentX = x + curentColumn * size.Width;
int curentY = y + currentRow * size.Height;
PictureBox picture = new PictureBox
{
Name = "pictureBox" + i,
Size = size,
Location = new Point(curentX, curentY),
BorderStyle = BorderStyle.Fixed3D,
SizeMode = PictureBoxSizeMode.Zoom,
Visible = true
};
this.Controls.Add(picture);
pictureBoxList.Add(picture);
}
However, you can also use two nested loops. First goes trough all the rows and second through all the columns, like this:
// size of the boxes
Size size = new Size(70, 60);
int totalBoxes = rows * columns;
List<PictureBox> pictureBoxList = new List<PictureBox>();
for (int row = 0; row < rows; row++)
{
int curentY = y + row * size.Height;
for (int col = 0; col < columns; col++)
{
int curentX = x + col * size.Width;
PictureBox picture = new PictureBox
{
Name = "pictureBox" + (row + col),
Size = size,
Location = new Point(curentX, curentY),
BorderStyle = BorderStyle.Fixed3D,
SizeMode = PictureBoxSizeMode.Zoom,
Visible = true
};
this.Controls.Add(picture);
pictureBoxList.Add(picture);
}
}
I personally prefer the nested loops way as it easier to read :)
From performance point of view both approaches should be the same.
Lately I've been working with OxyPlot library doing some charts. I was wondering if I can have a heatmap with comments for each one of the rectangles. looking forward to an answer.
I finally found that I needed to make a new class and extend the heatmap series and override the RenderLabels method in order to change its functionality.
protected override void RenderLabels(IRenderContext rc, OxyRect rect)
{
var clip = this.GetClippingRect();
int m = this.Data.GetLength(0);
int n = this.Data.GetLength(1);
double fontSize = (rect.Height / n) * this.LabelFontSize;
double left = this.X0;
double right = this.X1;
double bottom = this.Y0;
double top = this.Y1;
var s00 = this.Orientate(this.Transform(left, bottom)); // disorientate
var s11 = this.Orientate(this.Transform(right, top)); // disorientate
double sdx = (s11.X - s00.X) / (m - 1);
double sdy = (s11.Y - s00.Y) / (n - 1);
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
var point = this.Orientate(new ScreenPoint(s00.X + (i * sdx), s00.Y + (j * sdy))); // re-orientate
var v = GetValue(this.Data, i, j);
var color = this.ColorAxis.GetColor(v);
var hsv = color.ToHsv();
var textColor = hsv[2] > 0.6 ? OxyColors.Black : OxyColors.White;
var label = this.Labels[i, j];
rc.DrawClippedText(
clip,
point,
label,
textColor,
this.ActualFont,
fontSize,
500,
0,
HorizontalAlignment.Center,
VerticalAlignment.Middle);
}
}
}