Changing the bitmap shown in a PictureBox for different TrackBar values - winforms

I'm trying to use a TrackBar to control the image that is show in a PictureBox. There are 4 values for the TrackBar (0-4) and four images. The TrackBar's default value is 0 and currently I have set the Background image property to the image I would like to represent the 0 value (not sure if this is even the correct way to start).
so far i'v tried:
private void TrackBar1_Scroll(object sender, EventArgs e)
{
if (TrackBar1.Value == 1)
{
PictureBox1.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.Image2))
}
}
but this hasn't worked. I've got all the relevant images in the resources file all saved as bitmaps...
Any help would be greatly appreciated, still learning the ropes
Thanks
Harry

Not to worry I solved it myself, the code I had used worked, I'd just forgotten to update the scroll event property to the TrackBar1_Scroll Event

Related

Clearing previously loaded images in WinForm from resources

Purpose of my WinForm application is to load and display for a short while randomly selected picture from specific folder. I'm doing this using a PictureBox like so (this line gets adjusted by random number generator to generate different number file name):
pictureBox1.Image = Image.FromFile(#"C:\pics\1.png");
After a while it loads different image file, but looking at the Diagnostic View, I see that the Process Memory is rising by approx. 1MB with every image loaded. After about 100 pictures, the size rises by 100MB, even though the pictures were replaced. One of the timers that controls display duration includes some methods I found here to try and flush the image from resources:
private void displayDuration(object sender, EventArgs e)
{
pictureBox1.Visible = false;
pictureBox1.Image = null;
pictureBox1.Invalidate();
timer2.Enabled = false;
}
but to no avail. Memory keeps increasing, but the Tick function works since setting visibility to false works just fine.
How do I properly flush this image from memory once I don't need it anymore?
I'm trying not to include ImageList, but if you think it could resolve this memory issue, I could add it in.
Mr. Reza Aghaei was correct, Dispose() does the trick, I just used it wrong:
pictureBox1.Dispose();
which just ruined the pictureBox. Disposing the image in pictureBox is the correct way:
pictureBox1.Image.Dispose();
I shouldn't have given up on that method so early. Thank you very much.

Changing MediaElement source without Flicker

I have a simple video player that plays a series of videos using the WPF MediaElement. The videos together form one continuous film that move around a still image. At the end of each video the movement freezes on the final frame of the currently playing video. When I press a button the next video plays, which continues the movement around the still image. It's an application I'm going to use to give a speech. Effectively I've got a series of videos for which the last frame of each video is the same as the first frame of the next video.
I'm using a WPF MediaElement and changing the Source property when the user clicks on the mouse.
The problem that I have is that, when I change the Source property, the MediaElement becomes transparent while the next video is loaded. This means there is a flicker between videos. Is there any way of preventing this flicker? What other strategies could I use?
Here's some code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.x_MediaElement.MouseLeftButtonDown += x_MediaElement_MouseLeftButtonDown;
this.MouseLeftButtonDown += MainWindow_MouseLeftButtonDown;
this.WindowStyle = WindowStyle.None;
this.WindowState = WindowState.Maximized;
}
void MainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MoveNext();
}
private void MoveNext()
{
_sourceIndex++;
if (_sourceIndex >= _sources.Length)
_sourceIndex = 0;
Debug.WriteLine(string.Format("Playing {0}", _sources[_sourceIndex]));
this.x_MediaElement.Source = new Uri(_sources[_sourceIndex]);
this.x_MediaElement.Play();
}
private int _sourceIndex = -1;
private string[] _sources = new string[] {
//SOURCE GO HERE
};
void x_MediaElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MoveNext();
e.Handled = true;
}
}
I am gonna be honest with you. MediaElement has more bugs than you can count with fingers. Starting from that the mediaElement blows up after playing 20 videos(no more MediaEnded event, it will crash or something like that). And ofcourse the performance. Its not synchronized with vertical sync. So the video might actually seem laggy.
I advise you to look into DirectShow technology(essentially what WPF is based on, but you can switch renderer which will avoid lag). COnsidering that you will not be developing any professional application, I guess MediaElement will be fine.
However, MediaElement is the simplest option, and if it works for you, then keep working with it. As for your problem, I think there are few possible solutions:
Have two MediaElements and switch between them. If one video ends, start another vid in another MediaElement, as long as you play first frame on second mediaElement, hide the first mediaElement, and vice versa. You can poll for position, and maybe MediaStarted event. This way the flicker will be almost impossible to notice.
If you want fluent video playing without ANY flicker at all, there is GMFPlay. You can check it out. Though it's not MediaElement. But it can play videos simultaneously without any flicker.
Take screenshot of the last frame(you can take screenshots with WPF) and show it as Image while MediaElement is secretly loading.

How to make strokes disappear on an InkCanvas

I am completely new to this forum, and still a beginner on WPF.
I am working on a project that requires the strokes on an inkcanvas to be animated. One of the animations required is "disappearing". I want to make the selected strokes gradually disappear with the click of a button, but appear at the end of the animation.
Since there is no opacity property for stroke, I tried using the ColorAnimation class along with storyboards. I have failed to make this code work, as I cannot target the strokes either using themselves or using their names, since they don't have any.
Right now I am thinking of implementing this system by gradually changing the color of the strokes to the color of the background, and at the end, resetting it back to its initial value. This is a costly loop, but I have no other ideas.
I would appreciate it if there are any other solutions you might share with me.
Thanks in advance.
Edit: I have not answered the comments, as I was dealing with other parts of the same project.
I have tried using the Alpha values that are stored in the DrawingAttributes, but I cannot change the value as it is not a variable. The same goes with RGB values. I have no idea on how to make the strokes disappear in a loop. I have already implemented most of the project, so I just need something to slowly make them disappear. Below you can find an example where I change the stroke itself to animate it.
private int dropOffset = 1;
private void DropAnimation()
{
m = new Matrix();
m.Translate(0, dropOffset);
animStrokes.Transform(m, false);
YChange += dropOffset;
dropOffset += 2;
}
And in another class, I have
public void AnimateStrokes(Dispatcher canvasDispatch)
{
Stopwatch initial = Stopwatch.StartNew();
while (initial.ElapsedMilliseconds < 2000)
{
foreach (Animation ai in AnimationList)
{
ai.animateSelected();
}
canvasDispatch.Invoke(new Action(() => { }), DispatcherPriority.Render);
Thread.Sleep(50);
}
foreach (Animation a in AnimationList)
{
a.undoAnimation();
}
canvasDispatch.Invoke(new Action(() => { }), DispatcherPriority.Render);
}
I know that it's not healthy to pass dispatcher like this, but it suffices for now.
Thanks again in advance.
InkCanvas1.DefaultDrawingAttributes.Color = Color.FromArgb(100, 0, 255, 255);
Might be a bit late but help for others none the less! The 100 is the alpha value which basically acts like an opacity value!! Mess with that and you will be able to change how transparent your strokes are :)

printing with silverlight the same image multiple time

I have an image an a textbox. the user enters into the textbox the number of copies (N) and clicks print. The printer prints the photo N times (3 photos per page, one under the other).
Hiw would you do something like that? Do I need to first generate a silverlight page?
Silverlight has a really simple to use Printing API. I have recently been using it and learnt how to do so using the tutorial Melodatron listed, and this one over at the Visiblox site. This is specific to their charting library but I still found it very useful.
I am assuming that you only have 1 image to print at a time here, let me know if you have more. First, you need to set up a grid or something similar to put your photos in. You will need N number of rows in this grid. You'll have to do this in code behind as you have a certain number of rows you'd like to create, but this can easily be achieved by something like this:
Grid grid = new Grid();
// Set the column and row definitions
for (int i = 0; i < Number of rows; i++)
{
grid.RowDefinitions.Add(new RowDefinition());
}
That should set up your grid that you need. After you have the grid, you need to populate it with the images that you have. This is pretty straightforward, the only issue will be that your image can't be used multiple times - i.e. the image that you already have can only appear on the grid once. You will have to duplicate it in order to place it on the grid multiple times. I'm not sure how you are creating your images, but you could possibly create a new image based on the source path of the existing image? There is a thread on how to do this here. You'll need to give more details if you need help with that.
// Set the column and row definitions
for (int i = 0; i < Number of rows; i++)
{
// Duplicate your existing image here.
Image image = new Image();
grid.Children.Add(image);
Grid.SetRow(image, i);
}
All of the code above should be in this method:
private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
//Code from above...
e.PageVisual = grid;
}
In the button event handler where you wish to print, do this:
private void Button_Click(object sender, RoutedEventArgs e)
{
PrintDocument printDocument = new PrintDocument();
printDocument.PrintPage += new EventHandler<PrintPageEventArgs>(printDocument_PrintPage);
printDocument.Print("TITLE");
}
Hope this helps!
There's a pretty good tutorial (link below) with an example and source code on advanced printing techniques in Silverlight.
You will need to create the layout as a custom control, which should not be so difficult, but you won't need to display it.
http://www.silverlightshow.net/items/Advanced-printing-in-Silverlight-4.aspx
Hopefully this gets you started in the right direction.

How can I change the way InkCanvas draws?

I've searched for examples for this, but the ones I've ran across seem to focus on simpler stuff like setting the InkCanvas DefaultDrawingAttributes such as Width, Height, Color etc. Doesn't seem like there's a lot of material for this.
For example, if I hold down the mouse button I can see it drawing lines. What if I want to draw ellipses instead of lines, or draw ellipses around sampled points between the start and end of the line?
I know I can get new points with the StrokeCollected event, but beyond that I have no idea where to go. This guy seemed like he got msdn's code working, but I couldn't do it. I only know how to build the interface using XAML, and there doesn't seem to be a sample either.
edit
Created a StrokeCollection class variable called thisIsNotNice, initialized in the constructor and did this:
private void InkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
myInkCanvas.Strokes = thisIsNotNice;
foreach (StylusPoint p in e.Stroke.StylusPoints)
{
StylusPointCollection spc = new StylusPointCollection();
spc.Add(p);
Stroke s = new Stroke(spc);
s.DrawingAttributes.Height = 3;
s.DrawingAttributes.Width = 3;
thisIsNotNice.Add(s);
}
e.Handled = true;
}
But it doesn't work as it should. The ellipses are drawn, but the lines drawn by the mouse are still there. Also, for some reason, the first time it works as it should, drawing just the ellipses, but afterward it draws both the ellipses and the lines. But, if I do this instead:
private void InkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
myInkCanvas.Strokes = new System.Windows.Ink.StrokeCollection();
e.Handled = true;
}
The lines aren't kept on the screen. So, I don't understand why they aren't being erased in the above code.
If I do this:
private void InkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
foreach (Stroke s in myInkCanvas.Strokes)
System.Diagnostics.Trace.WriteLine(s);
e.Handled = true;
}
I can also see that the canvas contains the line strokes.
While erasing the strokes after they have been added to the collection is far from ideal, it at least does what I want. I could set up the line color to be the same of the background, but then I wouldn't be able to retrieve just the ellipses. I could copy them to a separate collection too, but that's just awful.
It sounds like you want to customize the way strokes appear on your inkCanvas. There are two separate things to consider here:
1) The way they look as the ink flows off the pen, before it is lifted (the DynamicRenderer, who runs on another thread to ensure that ink is always fast, is responsible for this. It sounds like you're happy with your solution to this already.
2) The way the eventual stroke sitting on the canvas looks. To customize this you might try subclassing Stroke, overriding:
protected override void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes);
Each time you get a strokeCollected (and here's the same horrible thing you were worried about but there you go), you remove the incoming stroke from the canvas and replace it with your custom implementation, stealing the stroke data from the incoming one.
Your implementation of DrawCore would look something like (pseudocode):
foreach(sp in this.StylusPoints)
drawingContext.DrawEllipse(RADIUS, sp.X, sp.Y)
And so as not to get the lines that normally happen you would not call base.DrawCore(context,attributes) at any point.

Resources