I am building a map editor to easily create 2d levels. To visualize how my level looks like I am using a canvas. On this canvas I can select which block is filled with a certain type ( like solid ). I did add click and drag but because I am live drawing on the canvas it goes very slow and if you draw at a decent speed it skips several block which needs to be drawn.
I already have tried several options ( doing it in another thread. Putting it first in a queue ) but none had a good result.
I use the following code to draw my rectangles:
if (currentMap != null)
{
mapCanvas.Children.Clear();
mapCanvas.Width = (currentMap.Breedte * blockScale);
mapCanvas.Height = (currentMap.Hoogte * blockScale);
for (int i = 0; i < currentMap.Hoogte; i++)
{
for (int j = 0; j < currentMap.Breedte; j++)
{
Rectangle blok = new Rectangle();
blok.Stroke = new SolidColorBrush(Colors.Black);
blok.StrokeThickness = 0.3;
blok.Width = blockScale;
blok.Height = blockScale;
switch (currentMap.GetElement(j, i))
{
case 0:
blok.Fill = new SolidColorBrush(Colors.LightGray);
break;
case 1:
blok.Fill = new SolidColorBrush(Colors.Red);
break;
case 2:
blok.Fill = new SolidColorBrush(Colors.Green);
break;
case 3:
blok.Fill = new SolidColorBrush(Colors.Orange);
break;
case 4:
blok.Fill = new SolidColorBrush(Colors.Yellow);
break;
default:
blok.Fill = new SolidColorBrush(Colors.Black);
break;
}
blok.SetValue(Canvas.LeftProperty, (double)(blockScale * j));
blok.SetValue(Canvas.TopProperty, (double)(blockScale * i));
mapCanvas.Children.Add(blok);
}
}
}
I did came across a solution to draw faster on a canvas on this link:
Speed up adding objects to Canvas In WPF
But the problem I cannot seem to get it working in my current project or a test project.
I hope you guys can help me to speed the drawing up or at least that it can recognize every block it needs to draw.
For further question please ask I will try to give as much detail as needed
Related
I'm trying to pull text from a PDF using iText7. I'm using the IEventListener to get all the parts of the page, though some of the text is rotated. I can find examples for how to insert rotated text into a PDF, but can't find anything about how I can tell if a given text segment is rotated.
Can anyone help ?
public void EventOccurred(IEventData data, EventType type)
{
PdfPart part = null;
switch (type)
{
case EventType.BEGIN_TEXT:
break;
case EventType.RENDER_TEXT:
part = new PdfTextPart(PageNumber, data as TextRenderInfo);
Parts.Add(part);
break;
case EventType.END_TEXT:
break;
case EventType.RENDER_IMAGE:
var imageData = data as ImageRenderInfo;
//this.HandleImage(imageData);
break;
case EventType.RENDER_PATH:
part = new PdfLinePart(PageNumber, data as PathRenderInfo);
Parts.Add(part);
break;
case EventType.CLIP_PATH_CHANGED:
break;
default:
break;
}
}
public PdfTextPart(Int32 pageNumber, TextRenderInfo info) : base(pageNumber)
{
Text = info.GetText();
var font = info.GetFont().GetFontProgram().GetFontNames();
Font = font.GetFontName();
if (font.IsItalic()) { this.IsItalic = true; }
if (font.IsBold()) { this.IsBold = true; }
if (font.IsUnderline()) { this.IsUnderline = true; }
}
TextRenderInfo has a base line. This base line is a LineSegment and as such has a start point and an end point. Now you merely have to determine the angle of the line between those two points.
I.e. for a TextRenderInfo info:
LineSegment baseline = info.GetBaseline();
Vector startPoint = baseline.GetStartPoint();
Vector endPoint = baseline.GetEndPoint();
Vector direction = endLocation.Subtract(startLocation);
double angle = Math.Atan2(direction.Get(Vector.I2), direction.Get(Vector.I1));
The result obviously is in radian measure.
You may additionally have to take into account the page rotation which (if I recall correctly) is not calculated into the coordinates above.
Is there any way of setting the Z-order of controls on a panel to always be on top when a new control is added? I am creating a card game and I have a Panel with the pictures of the cards in (a new picturebox for each card). When a new picture is added it automatically goes to the back of the panel. Is there any way so it will be always on top? I've tried 'SetChildIndex' but the name of each picturebox will be the same as I'm re-using code. Any help is appreciated. Thanks
private void DealPlayerCard(int cardNum)
{
string Card = Classes.Deck.GetCurrentCard();
PictureBox pb = new PictureBox() { Width = 172, Height = 240, SizeMode = PictureBoxSizeMode.StretchImage };
pb.ImageLocation = #"Cards\" + Card + ".png";
int order = 0;
switch (cardNum)
{
case 1:
pb.Location = new Point(0, 0);
order = 5;
break;
case 2:
pb.Location = new Point(60, 0);
order = 4;
break;
case 3:
pb.Location = new Point(120, 0);
order = 3;
break;
case 4:
pb.Location = new Point(180, 0);
order = 2;
break;
case 5:
pb.Location = new Point(240, 0);
order = 1;
break;
}
AddPlayerCard(pb, order);
}
public void AddPlayerCard(PictureBox pb, int order)
{
pnlPlayer.Controls.Add(pb);
pnlPlayer.Controls.SetChildIndex(pb, order);
}
EDIT
Using Sinatr's idea, I have now used the .Tag control property to give the z-order number to each of the controls and then whenever I add a control - simply loop through each control and set the z-order = .Tag property
private void DealPlayerCard(int cardNum)
{
string Card = Classes.Deck.GetCurrentCardPicture();
PictureBox pb = new PictureBox() { Width = 172, Height = 240, SizeMode = PictureBoxSizeMode.StretchImage };
pb.ImageLocation = #"Cards\" + Card + ".png";
switch (cardNum)
{
case 1:
pb.Location = new Point(0, 0);
pb.Tag = 5;
break;
case 2:
pb.Location = new Point(60, 0);
pb.Tag = 4;
break;
case 3:
pb.Location = new Point(120, 0);
pb.Tag = 3;
break;
case 4:
pb.Location = new Point(180, 0);
pb.Tag = 2;
break;
case 5:
pb.Location = new Point(240, 0);
pb.Tag = 1;
break;
}
AddPlayerCard(pb);
AddToHand("Player");
}
public void AddPlayerCard(PictureBox pb)
{
pnlPlayer.Controls.Add(pb);
foreach (Control Control in pnlPlayer.Controls)
{
pnlPlayer.Controls.SetChildIndex(Control, Int32.Parse(Control.Tag.ToString()));
}
}
You can use the BringToFront() method, available to every Winform control:
controlName.BringToFront();
This brings the control controlName to the top of the z-order, forcing it to have a z-order of 0.
You can SetChildIndex(System.Windows.Forms.Control child, int newIndex) to set the z-order.
A control with newIndex set to 0, is at the top of the z-order. Controls with higher newIndex will be positioned closer to the bottom.
I am trying to make my treeview's checkboxes bigger. According to MSDN it says by default state images are capped at 16x16 and in order to use larger state images I need to specify this entry in the app.config file:
<appSettings>
<add key="EnableWindowsFormsHighDpiAutoResizing" value="true" />
</appSettings>
I tried adding this to my app.config and it did not change a thing, problem is the framework seems to actually shrink the images when I use 32x32 checkboxes.
Here is how I draw and set the checkboxes in my treeview's constructor:
public class MultiStateTreeView : TreeView
{
public MultiStateTreeView() : base()
{
ImageList ilStateImages = new ImageList();
ilStateImages.ImageSize = new Size(32, 32);
for (int i = 0; i <= 4; i++)
{
Bitmap bmpCheckBox = new Bitmap(32, 32);
Graphics gfxCheckBox = Graphics.FromImage(bmpCheckBox);
switch (i)
{
case 0: cbsState = CheckBoxState.UncheckedNormal; break;
case 1: cbsState = CheckBoxState.CheckedNormal; break;
case 2: cbsState = CheckBoxState.MixedNormal; break;
case 3: cbsState = CheckBoxState.UncheckedDisabled; break;
case 4: cbsState = CheckBoxState.UncheckedDisabled; break;
}
CheckBoxRenderer.DrawCheckBox(gfxCheckBox, new Point(2, 2), cbsState);
gfxCheckBox.Save();
ilStateImages.Images.Add(bmpCheckBox);
}
base.CheckBoxes = true;
this.StateImageList = ilStateImages;
}
}
Is there something that I am missing?
I am trying to add a picturebox control to a panel which is created at runtime.
It is for a chess game I am working on. I want to add a picture box to each panel , an assigning the image to the control later. Here is what I have so far:
//Sets the number of rows on the chess board
for (int i = 0; i < 8; i++)
{
//Set the number of columns on the board
for (int j = 0; j < 8; j++)
{
ChessSquare sq = new ChessSquare(((char)(65 + i)).ToString(), 7- j);
sq.Color = (i + (j % 2)) % 2 == 0 ? Color.Black : Color.White;
Panel p = new Panel()
{
Size = new Size(blockSize, blockSize),
BackColor = sq.Color,
Tag = sq,
Location = new Point(blockSize * i + 15, blockSize * j + 15),
BackgroundImageLayout = ImageLayout.Stretch
};
p.MouseEnter += new EventHandler(squareMouseEnter);
p.MouseLeave += new EventHandler(squareMouseLeave);
p.Click += new EventHandler(squareMouseClick);
chessBoardPanels[i, j] = p;
groupBox1.Controls.Add(p);
}
}
//SetUp Board
SetUpBoad Setup = new SetUpBoad();
SetUpBoad(chessBoardPanels);
Since you already put the Panels into the panel-array (?)
chessBoardPanels[i, j] = p;
You can add the PictureBoxes either now or later..:
PictureBox pb = new PictureBox ();
pb.Size = ..
pb.BackColor = Color.Transparent;
chessBoardPanels[i,j].Controls.Add(pb);
To access them later you can cast their first Control to PictureBox:
PictureBox pb = (PictureBox)chessBoardPanels[i,j].Controls[0];
pb.Image = aQueenImage;
If you want to add a PictureBox only where a piece is you need to do checks:
if (chessBoardPanels[i,j].Controls.Count > 0)
{
PictureBox pb = (PictureBox)chessBoardPanels[i,j].Controls[0];
pb.Image = aQueenImage;
}
To move a piece from <i1,j1> to <i2, j2> you do as expected:
chessBoardPanels[i1,j1].Controls[0].Parent = chessBoardPanels[i2,j2];
I notice that you are hooking up mouse events. If you want to use them to move the pieces, remember that transparency will not work for overlapping controls in Winforms and so while a piece-Box is crossing Panels it will not have working tranparency around the Image.
While the pBox is nested in a Panel all is well but to move it you would have to first make it a child of the parent of those panels and only add it to the target Panel upon MouseUp; the coordinate corrections can be solved but the tranparency, if you need it, will be a bigger problem..
The usual advice it to consider drawing at least those board squares and maybe even the pieces onto a base board-Panel (or board-PictureBox)
community,
this is my first question here. to all the other problems i had there was often a answer on this side. for this i did not find one. here is my problem:
i have a chart and i want to add a vertical starpline at the point i click the mouse on the chart. this i working so far with that code:
chartSettlingCurve.ChartAreas[0].CursorX.SetCursorPixelPosition(new Point(e.X, e.Y), true);
double pX = chartSettlingCurve.ChartAreas[0].CursorX.Position; //X Axis coordinate Mouse
DataPoint dataPoint = chartSettlingCurve.Series[0].Points.FindByValue(nearestPreceedingValue(nearestPreceedingValue(pX)), "X");
labelTab3Test.Text = Convert.ToString(dataPoint);
DataPoint maxValuePoint = chartSettlingCurve.Series[0].Points.FindMaxByValue();
StripLine stripLineEnd = new StripLine();
stripLineEnd.BorderColor = Color.Blue;
stripLineEnd.IntervalOffset = dataPoint.XValue;
stripLineEnd.Text = "End";
this code generates a stripline at every point i click on the graph but i want just one line. so if ther still is a strip line it shopud be replaced by the new one at a other position.
woud be nice if you can help me. if you dont get my problem pleas ask.
thanks
a working solution is:
for (int j = 0; j < chartSettlingCurve.ChartAreas[0].AxisX.StripLines.Count; j++)
{
if (chartSettlingCurve.ChartAreas[0].AxisX.StripLines[j].Tag.ToString() == "end")
{
chartSettlingCurve.ChartAreas[0].AxisX.StripLines.RemoveAt(j);
j--;
}
}
or as an alternative:
bool loop = true;
while (loop)
{
loop = false;
foreach (var element in chartSettlingCurve.ChartAreas[0].AxisX.StripLines)
{
if (element.Tag.ToString() == "end")
{
chartSettlingCurve.ChartAreas[0].AxisX.StripLines.Remove(element);
loop = true;
break;
}
}
}
You can remove all striplines using code below;
while (chartSettlingCurve.ChartAreas[0].AxisX.StripLines.Count > 0)
{
chartSettlingCurve.ChartAreas[0].AxisX.StripLines.Remove(hartSettlingCurve.ChartAreas[0].AxisX.StripLines.Last());
}
than you can add some code.