TeeChart RedCross Error Continued - c#

This post corresponds to your answer on my previous post...
Before I upload a simple project for you, let me try something else: I noticed that when I swap the Points Series with a ColorGrid series the same thing happens, BUT, when I then (with the ColorGrid Series) use "MyColorGrid.YValues[gridPosition] = val" instead of MyColorGrid.Add(X, Y, Z) then it works. Is there a way I can use the Points Series in the same way, ie, allocate all the points the first time, and then just use XValues[idx] = x, and YValues[idx] = y to update the points? The problem seems to happen when I use the Add method, together with the Clear method. When I just update the values with XValues and YValues etc. the problem seems to be solved! The thing is, I can not get it to work on a Points Series...it was easy with the ColorGrid Series:
for (int r = 0; r < 128; r++)
{
for (int d = 0; d < 128; d++)
{
MyColorGrid.YValues[d * 128 + r] = some_value;
}
}
MyColorGrid.BeginUpdate();
MyColorGrid.EndUpdate();
Question 1: How do I achieve the same for the Points Series?
Question 2: If I succeed, how do I clear/delete points, without again having to "Add(x, y)" them afterwards?
Question 3: Is this the best way to use BeginUpdate/EndUpdate? Whats the difference? In general, what are the differences between all the available update methods, and how do I choose the correct one?
A few examples:
MyColorGrid.RefreshSeries
MyColorGrid.Repaint
MyTChart.Refresh
MyTChart.AutoRepaint
Regards
JD

Question 1: How do I achieve the same for the Points Series?
I suggest you use a similar code as next that works in correct way when you update the points.
Steema.TeeChart.Styles.Points points1;
Steema.TeeChart.TChart tChart1;
Random rnd;
public Form1()
{
InitializeComponent();
tChart1 = new Steema.TeeChart.TChart();
this.Controls.Add(tChart1);
tChart1.Aspect.View3D = false;
tChart1.Height = 400;
tChart1.Width = 500;
tChart1.Dock = DockStyle.Bottom;
points1 = new Steema.TeeChart.Styles.Points(tChart1.Chart);
rnd = new Random();
InitializeChart();
}
private void InitializeChart()
{
for (int i = 0; i < 128; i++)
{
points1.Add(i, rnd.Next(100));
}
tChart1.Refresh();
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 128; i++)
{
points1.XValues[i] = i+1;
points1.YValues[i] = rnd.Next(100);
}
points1.BeginUpdate();
points1.EndUpdate();
}
Question 2: If I succeed, how do I clear/delete points, without again having to "Add(x, y)" them afterwards?
I suggest you use the method SetNull() to make null the point as you don't want. You can do the same as next line of code:
points1.SetNull(3);
Question 3: Is this the best way to use BeginUpdate/EndUpdate? Whats the difference? In general, what are the differences between all the available update methods, and how do I choose the correct one? A few examples:
About BeginUpdate/EndUpdate:
The BeginUpdate method recalculates the function just one time, when finished adding points and the EndUpdate method is necessary used with .BeginUpdate to recalculate the function just once when finished adding points.
Therefore, you must use the both methods when you decide use BeginUpdate to update your series.
About other methods:
The differences between methods are explained by its definition that is found in help documentation and you can see in next lines:
Series.RefreshSeries: The RefreshSeries method notifies all dependent Series to recalculate their points again. Each Series has a DataSource property. When DataSource is a valid Series or DataSet component, Series get all point values from the DataSource and adds them as Series points. The RefreshSeries method forces the Series to Clear and get all points again from the DataSource component. The Refreshing process traverses the Series tree recursively
Series.Repaint: This Series method forces the whole Parent Chart to Repaint. You don't normally call Repaint directly. It can be used within derived TChartSeries components when changing their properties internally .
TChart.Refresh: Forces the control to invalidate its client area and immediately redraw itself and any child controls.
TChart.AutoRepaint: Use AutoRepaint false to disable Chart repainting whilst (for example) adding a large number of points to a Chart Series. This avoids repainting of the Chart whilst the points are added. AutoRepaint may be re-enabled, followed by a manual Repaint command when all points are added.
I hope will helps. If you have any questions please let me know.
Thanks,

Related

Unity Listing below and moving if disabled

so here is the idea i have a couple of game objects in a UI listed below each other so the idea is as follows
GameObject1
GameObject2
GameObject3
GameObject4
GameObject5
so i want to disable GameObject4 but when doing so GameObject5 will stay in the position its at i want it to automatically move up in to GameObject4's position
like so
GameObject1
GameObject2
GameObject3
GameObject5
and not
GameObject1
GameObject2
GameObject3
GameObject5
anyone have an Idea on how to do this?
Try creating an array of those objects (I think you mean UI elements) in an array, store their initial positions onStart in another array then loop to pop them from a stack.
Try fiddling with this to suit your needs:
public GameObject[] buttons;
float[] buttonPos;
private void Start()
{
buttonPos = new float[buttons.Length];
for (int i = 0; i < buttons.Length; i++)
{
buttonPos[i] = buttons[i].transform.position.y;
print(buttonPos[i]);
}
}
private void Update()
{
if (Input.GetKeyDown("space"))
{
DestroyButton(1);
}
}
void DestroyButton(int i)
{
Destroy(buttons[i]);
Stack(i);
}
void Stack(int i)
{
for ( int j= i; j < buttons.Length; j++)
{
if(j != buttons.Length-1)
buttons[j + 1].transform.position = new Vector3(buttons[j + 1].transform.position.x, buttonPos[j], buttons[j + 1].transform.position.z);
}
}
Your question is pretty unclear and incomplete; even the (missing) line-breaks are confusing...
Since it's a UI and your question contains spaces and not-spaces, I guess your gameObjects are in a VerticalLayoutGroup? Far fetched, if they are, shame on you for not stating that in your question.
If you want the elements to be disabled without the lower elements to "move up"
If I understood your question correctly, the solution would be to put your content as a child of an other one like so:
EDIT:
as #comphonia correctly suggests, it is preferable to have this menu made programmatically, with every button being a child of it's never disabled parent game object, and putting them into a List or array, such that you can disable them or reenable them individually

Region created from point array fills window

I have a weird problem concerning the Region object.
I created a method which returns the Region defined by an array of Point3D (which is just a 3-float struct) which are converted to PointF.(Face is the face of a 3d cube)
public Region GetRegion(params Point3D[] facePoints)
{
float distance = Camera3DLib.Camera3D.GetDistance();
PointF[] planePoints = new PointF[links.Length];
for (int i = 0; i < planePoints.Length; i++)
{
planePoints[i] = facePoints[i].ToPointF(distance);
}
GraphicsPath pth = new GraphicsPath();
pth.AddPolygon(planePoints);
return new Region(pth);
}
The problem is displaying this region.
When I use FillRegion, the graphics fills everything except the region.
To get the region needed to fill, I use the above method a number of times (Solid3D contains an array of Face3D and an array of vertices, I hope the purpose of the methods that I use are self explanatory by their names)
private static Region GetVisibleRegion(Solid3D s)
{
Region visible = new Region();
for (int i = 0; i < s.GetFaces().Length; i++)
{
Face3D face = s.GetFaces()[i];
Point3D[] facePoints = s.GetFaceVertices(i);
Region region = face.GetRegion(facePoints);
visible.Union(region);
}
return visible;
}
The drawing itself is done in a method called from the Form_paint event:
gr.FillRegion(Brushes.Blue, GetVisibleRegion(arr[0].Key));
gr is the graphics and arr is a dictionary who's key is a Solid3D.
This causes everything except the faces to be added to the Region.
What would be the cause of this?
I thought maybe the object, being passed by pointers between methods, is somehow getting reset (to default values of members) but I'm not so sure that's it.
PS: The code I wrote doesn't throw exceptions, so (I think) it's a logic or usage problem. If there are any questions about parts of the implementation that which aren't posted here (it's a lot of code :P) please ask.
Thanks!

Asynchronous method call in C#

We have such a situation. We have a canvas, on which some ammount of figures are rendered. It may be 1 or many more (for example thousand) and we need to animate their translation to another location (on button click) using storyboard:
internal void someStoryBoard(figure someFigure, double coordMoveToValue)
{
string sbName = "StoryBoard_" + figure.ID;
string regName = "figure_" + figure.ID;
try
{
cnvsGame.Resources.Remove(sbName);
cnvsGame.UnregisterName(regName);
}
catch{ }
someCanvas.RegisterName(regName, someFigure.Geometry);
var moveFigureYAnimation = new PointAnimation();
moveFigureYAnimation.From = new Point(someFigure.Geometry.Center.X, someFigure.Geometry.Center.Y);
moveFigureYAnimation.To = new Point(someFigure.eGeometry.Center.X, coordMoveToValue);
moveFigureYAnimation.Duration = TimeSpan.FromSeconds(0.5);
var sbFigureMove = new Storyboard();
Storyboard.SetTargetName(sbFigureMove, regName);
Storyboard.SetTargetProperty(sbFigureMove, new PropertyPath(Geometry.CenterProperty));
sbFigureMove.Children.Add(moveFigureYAnimation);
cnvsGame.Resources.Add(sbName, sbFigureMove);
sbFigureMove.Begin();
}
Figures are stored in list. We are calling this StoryBoard using for loop:
for(int i = 0; i<listOfFigures.Count; i++)
{
someStoryBoard(listOfFigures[i], someCoord);
}
But here's the problem: if we have a little amount of figures - code completes quickly. But if ammount is big - there is a delay after a button is clicked and before the figures begin to move.
So, here's the question: is it possible to call someStoryBoard method asynchronously? Is next algorithm possible -> When someStoryBoard is called it begins to move figure instantly, not waiting for whole for loop to complete.?
You can add actions into Dispatcher queue by calling Dispatcher.InvokeAsync. You can also specify dispatcher priority, depending on your requirements.
Please note that moving thousands of items can't be reliably fast, so you may need to rethink the drawing logic. If even starting animation is slow, it's highly likely animating won't be fast enough too.
You can try use async/await modifier
async internal Task someStoryBoard(figure someFigure, double coordMoveToValue)

charting markers not appearing on line

So I'm using Windows Forms Chart to generate graphs containing several lines that can create some clutter on the graph and need something to differentiate them other than color. There are too many points to using dotted or dashed lines as there is no observable difference between that and a continuous line. So what I'm hoping to do is to get markers with various shapes to show up on the lines like in Excel, for instance. Right now I'm have it coded like this
myChart.Series["MySeries"].ChartType = SeriesChartType.FastLine;
myChart.Series["MySeries"].MarkerStyle = MarkerStyle.Diamond;
What this does is put a diamond in the legend over that line, but it doesn't put diamonds on the actual line that is in the chart itself. Changing the marker size doesn't make a difference, unfortunately, and neither does changing the marker color. Is there a way to get that to happen. Thanks for reading, and any help you have.
EDIT:
Heres the relevant code.
Its data is held in a class that is the value-peice of a dictionary.
The class contains a list of doubles.
public void Charter(Color colorOfLine)
{
double xValue;
double yValue;
myChart.Series.Add("MySeries");
myChart.Series["MySeries"].ChartType.FastLine;
myChart.Series["MySeries"].ChartArea = "ChartArea1";
myChart.Series["MySeries"].Color = colorOfLine;
myChart.Series["MySeries"].MarkerStyle = MarkerStyle.Diamond;
myChart.Series["MySeries"].MarkerColor = Color.Black;
myChart.Series["MySeries"].MarkerSize = 5;
myChart.Series["MySeries"].MarkerBoarderColor = Color.DeepPink;
foreach (KeyValuePair<int, MyClass> Pair in MyDictionary)
{
xValue = Pair.Value.MyClassList[0];
yValue = Pair.Value.MyClassList[1];
myChart.Series["MySeries"].Points.AddXY(xValue, yValue);
}
}
I should add that I've played around with the MarkerStep, and MarkerBoarderWidth as well, all to no benefit. The issue seems to be that the marker simply isn't appearing on the actual lines in the chart itself. Also I'm using Visual Studio 2010 Express for what its worth. Thanks again for reading.
Use Line. Don't use FastLine. FastLine won't generate markers for you.
myChart.Series["MySeries"].ChartType = SeriesChartType.Line
Set the MarkerSize to something bigger:
myChart.Series["MySeries"].MarkerSize = 4;
ETA:
You may also need to set the color of the marker:
myChart.Series["MySeries"].MarkerColor = Color.Blue;
myChart.Series["MySeries"].Color = Color.Blue;

Cannot get the counters to move (game in C# with PictureBox).

I'm trying to learn C# (so go easy on me!) and as part of a coursework I have been asked to create a game called strikeout.
The game rules are very simple. It is simply a case of knocking one counter into another, with the aim of leaving one counter left on the screen.
I am having trouble simply moving one counter into another. I have created a number of picture boxes using a loop (to make up my board), and created an event handler using the loop. How can I use the single even handler to move all of my counters?
{
(...)
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
int x = j * (75);
int y = i * (75);
pictureBoxCounter[j, i] = new PictureBox();
pictureBoxCounter[j, i].Location = new System.Drawing.Point(x, y);
pictureBoxCounter[j, i].Size = new System.Drawing.Size(75, 75);
pictureBoxCounter[j, i].BackColor = System.Drawing.Color.Transparent;
panelGame.Controls.Add(pictureBoxCounter[j, i]);
this.pictureBoxCounter[j, i].Click += new System.EventHandler(this.pictureBoxCounter_Click);
}
}
} // end of some function
private void pictureBoxCounter_Click(object sender, EventArgs e)
{
//I need some code here but nothing seems to work :(
}
I've spent way to long on this problem. Even asked my tutor to help. Instead of helping he managed to break most of my code. So after fixing the problems he caused I am now back with a compiling program!
(When running the program you will need to enter player info to enable the start game button.)
If I can help with any other information don't hesitate to ask!
This programming problem appears intended to teach you about separation of concerns. If it isn't, it should be. (It is now!)
You have two problems, not one. (Actually, you have more than two, but you have two big ones.) One problem is: How do I create a set of objects representing the counters in this game, and what rules do those objects follow? The other problem is: How do I represent the counters on the screen?
If your solution to the first problem is to create a bunch of PictureBoxes, you're going down a rabbit hole that it's going to be tough to get back out of. You should solve the first problem first, and then the second problem.
Here's a rough sketch (very rough, because I don't know the rules of this game) of an object model that addresses the first problem:
public class Board
{
public const int Height = 8;
public const int Width = 8;
private Counters[Height][] Counters { get; set; }
public Counter GetCounter(int row, int col)
{
return Counters[row][col];
}
public void Initialize() { }
public void ExecuteMove(Counter c) { }
}
public class Counter
{
public int Row { get; set; }
public int Column { get; set; }
}
So, a Counter object knows where it is (its Row and Column). A Board object knows about all of the Counter objects, it knows how to find a Counter given its row and column, and it knows how to execute a move when a counter gets clicked on. (I don't know anything about the rules of the game, but they're going to live in the ExecuteMove method.
You can now trivially write a method that prints the board to the console:
public void PrintBoard(Board b)
{
for (int col = 0; col < board.Width; col ++)
{
for (int row = 0, row < board.Height; row++)
{
Counter c = board.GetCounter[row][col];
Console.Write(c == null ? " " : "*");
}
Console.WriteLine();
}
}
and a method to input a move:
public Counter InputMove(Board b)
{
string s;
Console.Write("Row: ");
s = Console.ReadLine();
int row = Convert.ToInt32(s);
if (s == "") return null;
Console.Write("Column: ");
s = Console.ReadLine();
if (s == "") return null;
int column = Convert.ToInt32(s);
return b.GetCounter(row, column);
}
...and now you have everything you need in order to code and test the ExecuteMove method. Get that working. I'll wait.
You done? Good. There are a couple of problems that you probably ran into that I haven't addressed. For instance, you probably discovered that when you move a Counter, you have to update both the board's array and the Counter itself. And you also probably discovered that you have to come up with some way of keeping track of what happens when a Counter is destroyed. Aren't you glad you weren't screwing around with mouse clicks and UI elements too?
Now for part two. Let's make a UI that knows how to talk to the Board. In your form, loop through the counters in the board, create a PictureBox for each (with its position based on the Row and Column properties), and add it to a Dictionary<PictureBox, Counter> called, say, Counters. You'll also want a Dictionary<Counter, PictureBox> called, say, PictureBoxes. These maps give you the ability to find a Counter given its PictureBox, and vice versa.
Attach this event handler to each PictureBox:
private void PictureBox_Click(object sender, EventArgs e)
{
PictureBox p = (PictureBox) sender;
Counter c = Counters[p];
Board.ExecuteMove(c);
}
(This, by the way, is the answer to your original question.)
Well, that's all well and good: you can click on a PictureBox, find its Counter, and execute the move. But how do you update the visual state of the game in the UI? That depends, a lot, on what the actual rules of the game are.
For instance, if clicking on a counter makes it disappear, you might add a Visible property to the Counter class and have the Board class's ExecuteMove update it. If, when a Counter becomes invisible, the other Counters in its row move left or right, the ExecuteMove method will have to update their Row and Column, and do something with the now-invisible Counter that was at that position.
But you already worked all of this out back when you tested all of the game logic, right? All you need to implement in your UI is an equivalent method to the one you built for printing it to the console. Only this one iterates through all of the Counters in the board, and updates their PictureBox based on their state.
There are a lot of subtleties that I'm glossing over here, mostly because a) I don't fully understand your problem and b) I'm not actually trying to do your homework for you.
You'll need to find the clicked picture box back in the Click event handler. You can use the sender argument for that. Trivially:
private void pictureBoxCounter_Click(object sender, EventArgs e)
{
PictureBox box = sender as PictureBox;
box.BackColor = System.Drawing.Color.Coral;
}
But you'll need to implement your game logic as well, which will require you know the box's location on the game board. You could use the PictureBox.Tag property for that. It could store a Point for example:
...
pictureBoxCounter[j, i].BackColor = System.Drawing.Color.Transparent;
pictureBoxCounter[j, i].Tag = new Point(j, i);
panelGame.Controls.Add(pictureBoxCounter[j, i]);
...
private void pictureBoxCounter_Click(object sender, EventArgs e)
{
PictureBox box = sender as PictureBox;
box.BackColor = System.Drawing.Color.Coral;
Point pos = (Point)box.Tag;
int row = pos.X;
int col = pos.Y;
//etc...
}
But you probably want to use a helper class that stores more info than just the row and column number.

Categories