I am working on a project using .Net Compact Framework 3.5 using C# 3.0.
I have a user control which receives data every 15 miliseconds and I have to draw shapes
like lines, rectangle, filled rectangles on user control.
I want to know what is the fastest way to draw these shapes, I am also open to use P/Invoke methods if there are some to increase performance and speed.
The code I am using is as follows:
private void DrawThreeFunctions(Graphics g)
{
// drawing back functions
if (DisplayFunction1.DrawOrder == DrawOrder.Back && GraphDataArray.Length > 0)
{
DrawFunction(g, DisplayFunction1, GraphDataArray[0]);
}
if (DisplayFunction2.DrawOrder == DrawOrder.Back && GraphDataArray.Length > 1)
{
DrawFunction(g, DisplayFunction2, GraphDataArray[1]);
}
if (DisplayFunction3.DrawOrder == DrawOrder.Back && GraphDataArray.Length > 2)
{
DrawFunction(g, DisplayFunction3, GraphDataArray[2]);
}
// drawing middle functions
if (DisplayFunction1.DrawOrder == DrawOrder.Middle && GraphDataArray.Length > 0)
{
DrawFunction(g, DisplayFunction1, GraphDataArray[0]);
}
if (DisplayFunction2.DrawOrder == DrawOrder.Middle && GraphDataArray.Length > 1)
{
DrawFunction(g, DisplayFunction2, GraphDataArray[1]);
}
if (DisplayFunction3.DrawOrder == DrawOrder.Middle && GraphDataArray.Length > 2)
{
DrawFunction(g, DisplayFunction3, GraphDataArray[2]);
}
// drawing front functions
if (DisplayFunction1.DrawOrder == DrawOrder.Front && GraphDataArray.Length > 0)
{
DrawFunction(g, DisplayFunction1, GraphDataArray[0]);
}
if (DisplayFunction2.DrawOrder == DrawOrder.Front && GraphDataArray.Length > 1)
{
DrawFunction(g, DisplayFunction2, GraphDataArray[1]);
}
if (DisplayFunction3.DrawOrder == DrawOrder.Front && GraphDataArray.Length > 2)
{
DrawFunction(g, DisplayFunction3, GraphDataArray[2]);
}
}
private void DrawFunction(Graphics g, DisplayFunction function, int[] data)
{
Color color = Utils.GetColor(function.Color);
switch (function.Shape)
{
case FunctionShape.StepLine:
DrawStepLines(g, data, color);
break;
case FunctionShape.Rectangle:
DrawFilledRectangles(g, data, color);
break;
case FunctionShape.FramedRectangle:
DrawFramedRectangles(g, data, color);
break;
case FunctionShape.Line:
DrawLines(g, data, color);
break;
default:
break;
}
}
#region Drawing methods
// drawing lines
private void DrawLines(Graphics g, int[] lineData, Color lineColor)
{
BarPositions = new List<int>();
List<Point> linePoints = new List<Point>();
int lineYPos = -1;
int lineXPos = FirstBarDrawPosition;
Point point = Point.Empty;
using (Pen linePen = new Pen(lineColor, 2.0f))
{
for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
{
if (base.GetBarEndPosition(k) > Width)
break;
lineXPos = GetTickPosition(k);
BarPositions.Add(lineXPos);
if (i < lineData.Length)
lineYPos = lineData[i];
else
continue;
point.X = lineXPos;
point.Y = lineYPos;
linePoints.Add(point);
}
if (linePoints.Any())
{
g.DrawLines(linePen, linePoints.ToArray());
}
}
}
// drawing framed rectangles
private void DrawFramedRectangles(Graphics g, int[] functionValues, Color functionColor)
{
BarPositions = new List<int>();
int barXPos = FirstBarDrawPosition;
Rectangle barRect = Rectangle.Empty;
barRect.Width = WidthOfBar - 1;
int barYPos = -1;
using (Pen barPen = new Pen(functionColor))
{
for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
{
if (base.GetBarEndPosition(k) > Width)
return;
BarPositions.Add(GetTickPosition(k));
if (i < functionValues.Length)
barYPos = functionValues[i];
else
continue;
//barRect = new Rectangle();
barRect.X = barXPos;
barRect.Y = barYPos;
//barRect.Width = WidthOfBar - 1;
barRect.Height = Height - barYPos;
g.DrawRectangle(barPen, barRect);
barXPos += (WidthOfBar + DistanceBetweenBars);
}
}
}
// drawing filled rectangles
private void DrawFilledRectangles(Graphics g, int[] functionValues, Color functionColor)
{
BarPositions = new List<int>();
int barXPos = FirstBarDrawPosition;
Rectangle barRect = Rectangle.Empty;
barRect.Width = WidthOfBar;
int barYPos = -1;
using (SolidBrush barBrush = new SolidBrush(functionColor))
{
for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
{
if (base.GetBarEndPosition(k) > Width)
return;
BarPositions.Add(GetTickPosition(k));
if (i < functionValues.Length)
barYPos = functionValues[i];
else
continue;
//barRect = new Rectangle();
barRect.X = barXPos;
barRect.Y = barYPos;
//barRect.Width = WidthOfBar;
barRect.Height = Height - barYPos;
g.FillRectangle(barBrush, barRect);
barXPos += (WidthOfBar + DistanceBetweenBars);
}
}
}
private void DrawStepLines(Graphics g, int[] lineData, Color lineColor)
{
BarPositions = new List<int>();
int lineYPos = -1;
int barXPos = FirstBarDrawPosition;
using (Pen linePen = new Pen(lineColor, 2.0f))
{
for (int i = FirstVisibleItemIndex, k = 0; i < _indexLimit; i++, k++)
{
if (base.GetBarEndPosition(k) > Width)
return;
BarPositions.Add(GetTickPosition(k));
if (i < lineData.Length)
lineYPos = lineData[i];
else
continue;
// draw third function line
//lineHeight = lineData[i];
g.DrawLine(linePen, barXPos, lineYPos, barXPos + WidthOfBar - 1, lineYPos);
barXPos += (WidthOfBar + DistanceBetweenBars);
}
}
}
I am using drawing order and shape like step line , line , framed rectangle ( just rectangle ) and rectangle is filled rectangle.
Because of performance critical application I want to know the fastest way of drawing these shapes.
Thanks in advance for any suggestion.
Are you familiar with double-buffering? Keep an offscreen image buffer to do your writes to as the changes come in. Then override the OnPaint to blit the whole image in one statement. Also, override the OnPaintBackground with a no-op to get rid of the default behavior of clearing the control to its backcolor on each paint.
Old as the hills, but here is an article on some best-practices on using GDI in the Compact Framework.
Related
I have TableLayoutPanel on windows form. I want mouse pointer cursor style is cross when the pointer on/near the cell border.
Edit I tried with mouse move event. I get the cell positions where the mouse point is moving.But I couldn't use this information and I was stuck. How can achieve that?
Edit: I fixed the problem. It is about size type. The code is working. I'm sharing it for those who have similar demands. Thanx.
bool calcCells = false;
List<float> XCoordinates = new List<float>();
List<float> YCoordinates = new List<float>();
public Form3()
{
InitializeComponent();
// Set the DoubleBuffered property via reflection (if needed)
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
tlp1.GetType().GetProperty("DoubleBuffered", flags).SetValue(tlp1, true);
tlp1.Layout += tlp1_Layout;
tlp1.CellPaint += tlp1_CellPaint;
tlp1.MouseMove += tlp1_MouseMove;
}
// Added the x coordinates of cell borders in a List
private void CreateXCoordinateList()
{
XCoordinates.Clear();
// first and last column sizetype is SizeType.Absoulute.
float tlpWidth = tlp1.Width- tlp1.ColumnStyles[0].Width - tlp1.ColumnStyles[tlp1.ColumnCount-1].Width;
float x = 0;
for (int i = 0; i < tlp1.ColumnCount; i++)
{
if(tlp1.ColumnStyles[i].SizeType==SizeType.Absolute)
x += tlp1.ColumnStyles[i].Width;
else if(tlp1.ColumnStyles[i].SizeType == SizeType.Percent)
{
double k = tlpWidth * tlp1.ColumnStyles[i].Width * 0.01;
x += Convert.ToSingle(k);
}
XCoordinates.Add(x);
}
}
// Added the y coordinates of cell borders in a List
private void CreateYCoordinateList()
{
YCoordinates.Clear();
// first and last row sizetype is SizeType.Absoulute.
float tlpHeight = tlp1.Height - tlp1.RowStyles[0].Height - tlp1.RowStyles[tlp1.RowCount - 1].Height;
float y = 0;
for (int i = 0; i < tlp1.RowCount; i++)
{
if (tlp1.RowStyles[i].SizeType == SizeType.Absolute)
y += tlp1.RowStyles[i].Height;
else if (tlp1.RowStyles[i].SizeType == SizeType.Percent)
{
double k = tlpHeight * tlp1.RowStyles[i].Height*0.01;
y += Convert.ToSingle(k);
}
YCoordinates.Add(y);
}
}
private void tlp1_Layout(object sender, LayoutEventArgs e) => calcCells = true;
private void tlp1_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
{
if (calcCells)
{
CreateXCoordinateList();
CreateYCoordinateList();
if (e.Column == tlp1.ColumnCount - 1 &&
e.Row == tlp1.RowCount - 1)
calcCells = false;
}
}
private void tlp1_MouseMove(object sender, MouseEventArgs e)
{
//Comparing the mouse pointer position with the cellborder coordinates,
//if the difference is less than and equal to 4, change the cursor style.
float x = e.Location.X;
float y = e.Location.Y;
if (MouseNearCellBorderXAxis(e) || MouseNearCellBorderYAxis(e))
tlp1.Cursor = Cursors.Cross;
else
tlp1.Cursor = Cursors.Default;
}
private bool MouseNearCellBorderXAxis(MouseEventArgs e)
{
float x = e.Location.X;
for (int i = 0; i < XCoordinates.Count; i++)
{
float Border = XCoordinates[i];
double difference = Math.Abs(x - Border);
if (difference <= 4)
return true;
}
return false;
}
private bool MouseNearCellBorderYAxis(MouseEventArgs e)
{
float y = e.Location.Y;
for (int i = 0; i < YCoordinates.Count; i++)
{
float Border = YCoordinates[i];
double difference = Math.Abs(y - Border);
if (difference <= 4)
return true;
}
return false;
}
If I get what you're asking, provided you have controls in the cells of the TableLayoutPanel all one would have to do is set the different cursors one time for:
Main form (Arrow)
Table layout panel (Cross)
The controls therein contained (e.g. Hand)
Everything else should happen on its own.
public MainForm()
{
InitializeComponent();
// MainForm has ARROW
this.Cursor = Cursors.Arrow;
// TableLayoutPanel has CROSS
tableLayoutPanel.Cursor = Cursors.Cross;
int key = 0; string text;
for (int column = 0; column < tableLayoutPanel.ColumnCount; column++)
for (int row = 0; row < tableLayoutPanel.RowCount; row++)
{
switch (++key)
{
case 10: text = "*"; break;
case 11: text = "0"; break;
case 12: text = "#"; break;
default: text = $"{key}"; break;
}
tableLayoutPanel.Controls.Add(new Label
{
BackColor = Color.LightGreen,
Anchor = (AnchorStyles)0xF,
Margin = new Padding(10),
Text = text,
TextAlign = ContentAlignment.MiddleCenter,
// Controls in the table have HAND
Cursor = Cursors.Hand,
});
}
}
I am working on a game where a user moves around a 10x10 grid of buttons. The buttons are added to a 2d array and are displayed as shown below. Currently I have the starting position (black player tile) set to index 1 when the form loads. What I am trying to figure out is how I can introduce a button event method that I can use to navigate the tiles.
Here is what the grid looks like:
And here is the code:
private readonly int _xAxis = 10;
private readonly int _yAxis = 10;
private int _count = 1;
private void DrawButtonArray()
{
Button[] buttons = new Button[_xAxis * _yAxis];
int index = 0;
for (int i = 0; i < _xAxis; i++)
{
for (int j = 0; j < _yAxis; j++)
{
Button gridBtn = new Button
{
Size = new Size(60, 55),
Location = new Point(175 + j * 60, 55 + i * 55),
Text = _count.ToString()
};
gridBtn.ForeColor = Color.FromArgb(64, 64, 64);
buttons[index++] = gridBtn;
_count++;
Controls.Add(gridBtn);
if (index == 1)
{
gridBtn.BackColor = Color.Black;
}
}
}
}
What Id hope to achieve is a mouse click event (or possibly WASD key press) that moves the "player" from one button to another. The current idea I have is to set the next button that is clicked to the colour of the current position, then set the current positions colour to the default grey. I just need to know how I could add these event args to the method that doesn't contain them. How might I add them?
I created a method that works, but it might not be the best:
private void DrawButtonArray()
{
Button[] buttons = new Button[_xAxis * _yAxis];
int currentIndex = 0;
for (int i = 0; i < _xAxis; i++)
{
for (int j = 0; j < _yAxis; j++)
{
Button gridBtn = new Button
{
Size = new Size(60, 55),
Location = new Point(175 + j * 60, 55 + i * 55),
Text = _count.ToString()
};
gridBtn.ForeColor = Color.FromArgb(64, 64, 64);
if (currentIndex == 0)
{
gridBtn.BackColor = Color.FromArgb(0, 0, 0);
}
buttons[currentIndex++] = gridBtn;
_count++;
Controls.Add(gridBtn);
}
}
currentIndex = 1;
foreach (Button nextIndex in buttons)
{
nextIndex.Click += (s, e) =>
{
if (nextIndex.Text == (currentIndex + 1).ToString()
|| nextIndex.Text == currentIndex.ToString()
|| nextIndex.Text == (currentIndex - 1).ToString()
|| nextIndex.Text == (currentIndex + 10).ToString()
|| nextIndex.Text == (currentIndex - 10).ToString())
{
buttons[currentIndex - 1].BackColor = Color.FromArgb(64, 64, 64);
currentIndex = int.Parse(nextIndex.Text);
nextIndex.BackColor = Color.Black;
}
else
{
MessageBox.Show("Invalid Move");
}
};
}
}
So Im making tetris and I dont know how to draw the blocks( L,I,Z etc) I have one block as Texture2D and every class for the blocks look like this:
namespace Tetris
{
public class ZBlock
{
Color Color;
const int x = 4;
const int y = 4;
bool[,] vorm;
public bool[,] zblock()
{
vorm = new bool[x, y];
for(int i=0; i< x; i++)
for (int j=0; j<y; j++)
{
vorm[i, j] = false;
vorm[0, 0] = true;
vorm[1, 0] = true;
vorm[1, 1] = true;
vorm[2, 1] = true;
}
Color = Color.Purple;
return vorm;
}
}
and this is the block class:
namespace Tetris
{
public class Block
{
Texture2D block;
Vector2 BlockPosition = new Vector2(30, 30);
float FallTimer;
Random Random = new Random();
ZBlock zBlock = new ZBlock();
TBlock tBlock = new TBlock();
SBlock sBlock = new SBlock();
OBlock oBlock = new OBlock();
JBlock jBlock = new JBlock();
LBlock lBlock = new LBlock();
IBlock iblock = new IBlock();
public bool[,] blockvorm()
{
bool[,] vorm;
vorm = new bool[4, 4];
vorm[3, 3] = false;
int r = Random.Next(7);
if (r == 0)
{
ZBlock.zblock();
}
else if (r == 1)
{
TBlock.tblock();
}
else if (r == 2)
{
SBlock.sblock();
}
else if (r == 3)
{
OBlock.oblock();
}
else if (r == 4)
{
JBlock.jblock();
}
else if (r == 5)
{
LBlock.lblock();
}
else if (r == 6)
{
IBlock.iblock();
}
return vorm;
}
public TBlock TBlock
{
get { return tBlock; }
}
public ZBlock ZBlock
{
get { return zBlock; }
}
public SBlock SBlock
{
get { return sBlock; }
}
public OBlock OBlock
{
get { return oBlock; }
}
public JBlock JBlock
{
get { return jBlock; }
}
public LBlock LBlock
{
get { return lBlock; }
}
public IBlock IBlock
{
get { return iblock; }
}
public void Draw(GameTime gameTime, SpriteBatch spriteBatch, ContentManager Content)
{
block = Content.Load<Texture2D>("Block");
int[,] Grid = Tetris.GameWorld.TetrisGrid;
spriteBatch.Begin();
spriteBatch.Draw(?????????????);
spriteBatch.End();
}
So the problem is: I dont know how to draw those blocks (I know how to draw one block but I want the complete ones). I thought maybe ZBlock.vorm or ZBLock.zblock but both give errors.
Does anyone know how to draw the blocks?
Ok so here is a partial answer. What you want to do is basically just draw each block with a certain offset from the next block equal to: blockWidth / 2 in pixels. This means that the blocks will be correctly orientated without overlap.
Here is what you should put in the draw statement:
public void Draw(int theXPosition, int theYPosition, Color theColor, SpriteBatch theSpriteBatch, Texture2D theBlockTexture)
{
int aTextureStartX = Color * Convert.ToInt32(mBlockSize);
for (int aBlock = 0; aBlock < mNumberOfBlocks; aBlock++)
{
int aXPosition = (int)(theXPosition + (CurrentShape[Rotation, aBlock, 0] * mBlockSize));
int aYPosition = (int)(theYPosition + (CurrentShape[Rotation, aBlock, 1] * mBlockSize));
theSpriteBatch.Draw(theBlockTexture, new Rectangle(aXPosition, aYPosition, mBlockSize, mBlockSize), new Rectangle(aTextureStartX, 0, mBlockSize, mBlockSize),
}
}
This is from a blog: http://www.xnadevelopment.com/tutorials/fallingblocksyoumovetomakelines/fallingblocksyoumovetomakelines.shtml
The source code is at the top of the page.
I am recreating the classic game Reversi using c# in order to improve my skills at programming
but I have a problem when I check the colors. So far I have managed to revers colors from left and from top but it doesn't work correctly it only reverses the colors when I hit the last square on the board.
Any help would be much appreciated
Here is an image that may explain what I mean (the code is below) mean
The code that I have:
namespace praprevers
{
public partial class Form1 : Form
{
private Button[,] squares;
//private Button[,] r0;
public Form1()
{
InitializeComponent();
squares = new Button[4, 4];
squares = new Button[,] {
{btn_0_0, btn_0_1, btn_0_2, btn_0_3},
{btn_1_0, btn_1_1, btn_1_2, btn_1_3},
{btn_2_0, btn_2_1, btn_2_2, btn_2_3},
{btn_3_0, btn_3_1, btn_3_2, btn_3_3}
};
}
int _turn = 0;
private void DrawColor(object sender, EventArgs e)
{
Button b = sender as Button;
string[] btnData = b.Name.Split('_');
int x = int.Parse(btnData[1]);
int y = int.Parse(btnData[2]);
//check for possible combinations
int top = x - 3;
int botton = x +3;
int left = y - 3;
int right = y + 3;
for (int l = 0; l < 4; ++l)
{
if (top >= 0 && squares[top, y].BackColor == Color.Black)
{
squares[top + l, y].BackColor = Color.Black;
}
else if (left >= 0 && squares[x, left].BackColor == Color.Black)
{
squares[x, left + l].BackColor = Color.Black;
}
}
if (_turn == 0)
{
_turn = 1;
b.BackColor = Color.Black;
}
else
{
_turn = 0;
b.BackColor = Color.Red;
}
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (Button sqrr in squares)
{
sqrr.Click += new System.EventHandler(this.DrawColor);
}
}
}
}
I am trying add a page when horizontal or the x position is greater than a counter in order to keep a right side margin. When I run the code I end up in an infinate loop of hundreds of pages all displaying the same first page graphics. Thinking it might have to do with my lack of understanding HasMorePages. I could use some help. Thanks.
public static class PrintWave
{
public static void PrintPreWave()
{
PrintDocument pd = new PrintDocument();
if (WaveTools.MySettings == null)
{
pd.DefaultPageSettings.Landscape = true;
}
else
{
pd.DefaultPageSettings = WaveTools.MySettings;
}
pd.OriginAtMargins = true;
pd.PrintPage += new PrintPageEventHandler(OnPrintPage);
PrintDialog dlg = new PrintDialog();
PrintPreviewDialog printPreviewDlg = new PrintPreviewDialog();
printPreviewDlg.Document = pd;
Form p = (Form)printPreviewDlg;
p.WindowState = FormWindowState.Maximized;
printPreviewDlg.ShowDialog();
}
private static void OnPrintPage(object sender, PrintPageEventArgs e)
{
string MyTag = string.Empty;
MyTag = WaveActions.ActiveId;
Wave MyWave = WaveHolder.FindWave(MyTag);
int MyCount = 0;
int xOffset = e.MarginBounds.Location.X;
int yOffset = e.MarginBounds.Location.Y;
if (MyWave != null)
{
Graphics g = e.Graphics;
g.SetClip(e.PageBounds);
Pen MyPen = new Pen(WaveTools.WaveColor, WaveTools.PenWidth);
float dx = (float)e.PageBounds.Width / MyWave.NumSamples;
float dy = (float)e.PageBounds.Height / 255;
if (MyWave.Normal == false)
{
g.ScaleTransform(dx, dy);
}
for (int i = 0; i < MyWave.NumSamples - 1; i++)
{
g.DrawLine(MyPen, i, MyWave.Data[i], i + 1, MyWave.Data[i + 1]);
MyCount = MyCount + 1;
if (MyCount > e.MarginBounds.Width)
{
e.HasMorePages = true;
MyCount = 0;
return;
}
else
{
e.HasMorePages = false;
return;
}
}
}
}
}
}
for (int i = 0; i < MyWave.NumSamples - 1; i++)
That's the core problem statement, you start at 0 every time PrintPage gets called. You need to resume where you left off on the previous page. Make the i variable a field of your class instead of a local variable. Implement the BeginPrint event to set it to zero.
The else clause inside the loop need to be deleted.