Need To Add Text To Each End Of A Path - wpf

I am drawing a diagram of a switch network in WPF. I can add the switches and the connections between them to the diagram. the connections are drawn as Path with LineGeometry as the Data:
Shapes.Path path1;
path1 = new Shapes.Path();
path1.Stroke = Brushes.Black;
path1.StrokeThickness = 1;
LineGeometry line1 = new LineGeometry();
path1.Data = line1;
I add the line to the thumb that I am using to represent the switch:
SwitchAsThumb thumb1 = new SwitchAsThumb;
thumb1.StartLines.Add(line1);
Where SwitchAsThumb is defined as:
public class SwitchAsThumb : Thumb
{
public List<LineGeometry> EndLines { get; private set; }
public List<LineGeometry> StartLines { get; private set; }
}
and this method in my window xaml.cs file to update the end point position of the path:
public void UpdateSwitchConnections(SwitchAsThumb thumb)
{
double left = Canvas.GetLeft(thumb);
double top = Canvas.GetTop(thumb);
for (int i = 0; i < thumb.StartLines.Count; i++)
thumb.StartLines[i].StartPoint = new Point(left + thumb.ActualWidth / 2, top + thumb.ActualHeight / 2);
for (int i = 0; i < thumb.EndLines.Count; i++)
thumb.EndLines[i].EndPoint = new Point(left + thumb.ActualWidth / 2, top + thumb.ActualHeight / 2);
}
I was thinking I could place labels or similar at the same points on the canvas when the lines are updated, but I'm not sure the labels would move when the user drags the switches around to re-arrange the diagram. The method I've implemented to re-draw the thumbs when the user drags them around could probably be updated to move the labels but I'm hoping there's a cleaner solution.

Related

How to calculate a text size?

Apparently the com.codename1.ui.plaf.LookAndFeel.getTextAreaSize(TextArea, boolean) doesn't return an exact text size.
I would like to determine the size of a speech bubble, or the size of a possibly multi-line text in a speech bubble.
How would I do that? Is there a utility method for that somewhere in CN1?
This returns the preferred size. With multiline text we size based on the number of rows/columns since the text is modifiable and scrollable its content isn't fully taken into consideration for this calculation. Even when it is taken into consideration this can't be 100% accurate as even 1 pixel difference in width can cause a line break which will reflow everything. There are many special cases involved with text sizing so you shouldn't rely on accuracy. Try using setActAsLabel or SpanLabel.
Apparently there is currently no text area component in Codename One that can be used to size to its content.
Here is a custom one that does that:
private class Hint extends Component {
final String text;
final int rowsGap = new TextArea().getRowsGap();
private Hint(String aText) {
text = aText;
}
#Override
protected Dimension calcPreferredSize() {
int prefW = 0;
int prefH = 0;
Style style = getStyle();
Font font = style.getFont();
List<String> lines = StringUtil.tokenize(text, "\n");
int tally = 0;
for (String line: lines) {
tally++;
prefW = font.stringWidth(line);
}
prefH = tally * (font.getHeight() + rowsGap);
prefW += getUnselectedStyle().getHorizontalPadding() + 5;
prefH += style.getPaddingTop() + style.getPaddingBottom();
if(style.getBorder() != null) {
prefW = Math.max(style.getBorder().getMinimumWidth(), prefW);
prefH = Math.max(style.getBorder().getMinimumHeight(), prefH);
}
if(getUIManager().getLookAndFeel().isBackgroundImageDetermineSize() && style.getBgImage() != null) {
prefW = Math.max(style.getBgImage().getWidth(), prefW);
prefH = Math.max(style.getBgImage().getHeight(), prefH);
}
return new Dimension(prefW, prefH);
}
#Override
public void paint(Graphics aGraphics) {
Style style = getStyle();
int xLeft = style.getPaddingLeft(false), yTop = style.getPaddingTop();
List<String> lines = StringUtil.tokenize(text, "\n");
int y = yTop;
aGraphics.setColor(0x000000);
for (String line: lines) {
aGraphics.drawString(line, getX() + xLeft, getY() + y);
y += style.getFont().getHeight() + rowsGap;
}
}
}

Array displaying images, need to make another method that takes a paramter NUM to order how many pictures are shown

I explained that horridly in the title, and I apologize, am very new to java and don't quite understand some of it yet.
Anyway,
My cat animation runs to the middle of the screen, scratches twice, then continues to run to the end, is there anyway to write a method that will take an INT NUM and make the cat scratch x amount of times? Not sure how to go about doing this.
Any help would be much appreciated
Here is my current code
/** Run the animation. */
public void nekoRun() {
moveIn();
scratch();
//scratch2(5);
moveOut();
}
/* Move Neko to the centre of the panel. */
private void moveIn() {
for (int i = 0; i < getWidth()/2; i+=10) {
xPos = i;
// swap images
if (currentImage == nekoPics[0])
currentImage = nekoPics[1];
else
currentImage = nekoPics[0];
repaint();
pause(150);
}
}
//neko stops and scratches in the middle of the panel twice
private void scratch() {
for (int i = 0; i < 10; i++) {
// Swap images.
currentImageIndex = nextImageList[currentImageIndex];
currentImage = nekoPics[currentImageIndex];
repaint();
pause(150);
}
}
//Neko runs to the end of the panel
private void moveOut() {
for (int i = xPos; i < getWidth(); i+=10) {
xPos = i;
// swap images
if (currentImage == nekoPics[0])
currentImage = nekoPics[1];
else
currentImage = nekoPics[0];
repaint();
pause(150);
}
}

Clipping image using Path in Silverlight

How to clip image in Silverlight using custom Path (in code behind, not in XAML).
I have puzzle piece like shape written in path and want to use it to clip any image.
Currently it works by clipping using rectangle, The code is (C#):
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
int NUM_COLUMN = 8;
int NUM_ROW = 8;
double gridWidth = 60;
double gridHeight = 60;
string url = "Images/Sun.png";
// C#
for (int i = 0; i < NUM_COLUMN; i++)
{
for (int j = 0; j < NUM_ROW; j++)
{
double offsetX = (double)i * gridWidth;
double offsetY = (double)j * gridHeight;
Image image = new Image();
image.Source = new BitmapImage(new Uri(url, UriKind.Relative));
// clip the image
RectangleGeometry r = new RectangleGeometry();
r.Rect = new Rect(offsetX, offsetY, gridWidth, gridHeight);
image.Clip = r;
this.ClipCanvas.Children.Add(image);
}
}
}
There is only one Canvas in XAML called ClipCanvas.
Okay, not ideal. But works from the code-behind
Image image = XamlReader.Load(#"<Image xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" Clip=""M 41.1,33.7 C 41.1,33.7 39.9,32.2 39.9,30.8 C 39.9,30.6 39.5,29.8 39.3,29.5 C 39.1,29.3 38.4,28.6 37.8,28.2 C 37.2,27.9 35,26.6 34.6,22.4 Z "" />") as Image;
image.Source = new BitmapImage(new Uri("Desert.jpg", UriKind.Relative));
Set up in the clip in Xaml, and create the Image using an XamlReader. Tried other approaches, and this was the only one that worked.

Subclassed ListView column 0 displays corrupted text on Windows 7

Windows 7 (64 bit), .NET 4 (32 bit app)
I have a subclassed System.Windows.Forms.ListView comprising 2 columns displayed
in "Details" view. Only text fields are involved. The list comprises about 100
rows. On initial display all fields are drawn clearly but when scrolling or
"paging" with the scroll bar the text of some fields in the first column becomes
unreadable. It appears to be overwriten with random lines and blotches.
Is there anything that I can do to ensure that the text is clearly drawn in column 0?
The effect is diminished (clarity improved) when using remote desktop across a
LAN.
The effect disappears (all text is drawn clearly) when using remote desktop
across a WAN.
The ListView has always drawn perfectly on Windows XP.
For the purposes of a stripped down test, column header and DrawItem calls are ingored. The problem area is OnDrawSubItem which comprises the code
protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
{
using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap))
{
Rectangle rect = new Rectangle(e.Bounds.Left
,e.Bounds.Top, e.Bounds.Width, e.Bounds.Height);
e.Graphics.DrawString(e.SubItem.Text, this.Font, Brushes.Black
,rect, sf);
}
base.OnDrawSubItem(e);
}
The following is the complete code that reproduces the problem:
using System;
using System.Windows.Forms;
using System.Drawing;
///
/// Build by saving to a file called LVTrial.cs and then executing "csc LVTrial.cs"
/// Scroll list up and down on a windows 7 box and the first column of text is corrupted.
///
class MyListView : ListView
{
Random randomiser = new Random();
private const int NUM_ROWS = 100;
private const int NUM_COLS = 2;
public MyListView()
{
this.Location = new System.Drawing.Point(23, 25);
this.OwnerDraw = true;
this.Size = new System.Drawing.Size(625, 387);
this.TabIndex = 0;
this.UseCompatibleStateImageBehavior = false;
this.View = System.Windows.Forms.View.Details;
for (int ii = 0; ii < NUM_COLS; ii++)
{
this.Columns.Add((
(System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())));
}
for (int ii = 0; ii < NUM_ROWS; ii++)
{
this.Items.Add( new ListViewItem(
new string[NUM_COLS] { CreateRandomString(1, 6), CreateRandomString(1, 6) } ) );
}
}
protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
{
using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap))
{
Rectangle rect = new Rectangle(e.Bounds.Left
,e.Bounds.Top, e.Bounds.Width, e.Bounds.Height);
e.Graphics.DrawString(e.SubItem.Text, this.Font, Brushes.Black
,rect, sf);
}
base.OnDrawSubItem(e);
}
private string CreateRandomString(int minLength, int maxLength)
{
string str = string.Empty;
int length = randomiser.Next(minLength, maxLength + 1);
for (int ii = 0; ii < length; ii++)
{
int asciiChar = randomiser.Next(32, 126); // ascii range
str += Convert.ToChar(asciiChar);
}
return str;
}
}
class LVTrial : Form
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new LVTrial());
}
private LVTrial()
{
MyListView myListView = new MyListView();
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(674, 440);
this.Controls.Add(myListView);
this.Text = "LVTrial";
}
}
I have recorded this as a Windows 7 bug at https://connect.microsoft.com/VisualStudio/feedback/details/657909/subclassed-listview-column-0-displays-corrupted-text-on-windows-7
My own workaround for the problem was to insert an additional column at position 0. I now draw a rectangle with a transparent brush in column 0 for each item. All of which stops the text in the column to the right being drawn corrupt. I imagine drawing an image would achieve the same thing but I have not tried it. You can't hide this dummy column as the problem simply transfers to the second column (i.e. the first visible coolumn).
Another tip is that it seems to be performance related. The bug was more likely to occur with 100 items in the list view than 10,000.

how to draw N lines per inch?

my code below is supposed to display N lines per inch. instead i get a little more than N lines per inch. the distance between lines is somewhat smaller. in addition, changing the screen resolution makes the distance between lines change too. does anyone know how to handle that?
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace MyApp
{
class MyControl : Control
{
private readonly ContainerVisual container = new ContainerVisual();
private readonly DrawingVisual drawing = new DrawingVisual();
private void RenderDrawing()
{
var s = PresentationSource.FromVisual(this);
var dpiX = 96 * s.CompositionTarget.TransformToDevice.M11;
var dpiY = 96 * s.CompositionTarget.TransformToDevice.M22;
double N = 1;
using (var c = drawing.RenderOpen())
{
var p = new Pen(new SolidColorBrush(Colors.Black), 1);
for (int i = 0; i < 10; i++)
{
var x = i * dpiX / N;
c.DrawLine(p, new Point(x, 0), new Point(x, 100));
}
}
}
protected override Size ArrangeOverride(Size s)
{
RenderDrawing();
return s;
}
protected override Visual GetVisualChild(int index)
{
return container;
}
protected override Size MeasureOverride(Size s)
{
return new Size();
}
protected override int VisualChildrenCount
{
get { return 1; }
}
public MyControl()
{
container.Children.Add(drawing);
AddVisualChild(container);
}
}
}
this article seems to discuss the same problem: WPF DPI issues
there is no solution to this problem other than asking the user to set the correct DPI settings that correspond to the physical DPI of the screen. a workaround that i found that makes life a little easier is to use WPF application level scaling as described here: http://www.odewit.net/ArticleContent.aspx?id=WpfDpiScaling&lang=en&format=html
Not sure if this would accomplish what you are looking for, but it should help if the issue has to do with rounding. As I said in comments, your code looks mostly correct, I think it is a rounding issue with the dpi computation. Since you are desiring to render based on 96 dpi, compute the coordinates based on 96dpi and then convert the points to your device. I wrote this more for clarity, you could use a single array of points and just remember that i is the start point and i+1 is the end point and then you would only have to make a single call to transform the points.
private void RenderDrawing()
{
var s = PresentationSource.FromVisual(this);
var dpiX = 96;
int numberOfLines = 10;
double N = 1;
double spacing = dpiX / N;
var startPoints = new Point[numberOfLines]();
var endPoints = new Point[numberOfLines]();
for (int i = 0; i < numberOfLines; i++)
{
var x = i * spacing;
startPoints[i] = new Point(x, 0);
endPoints[i] = new Point(x, 100);
}
s.CompositionTarget.TransformToDevice.Transform(startPoints);
s.CompositionTarget.TransformToDevice.Transform(endPoints);
using (var c = drawing.RenderOpen())
{
using (var p = new Pen(new SolidColorBrush(Colors.Black), 1))
{
for(int i=0; i < numberOfLines; i++)
{
c.DrawLine(p, startPoints[i], endPoints[i]);
}
}
}
}

Resources