1

I have C# fading out a picture box, when I click a button, and after the fade out the same picture box will fade in the next image. Currently, I have the fade out code placed both in the fade out and fade in conditions. (I still need to rewrite the code for fade in.) Once the code hits the logic for the second image, the code just loops through until the conditions turn up false and exits without changing the display. How can I correct my code to get the same effect going on the second image? Also, if anyone knows how to rewrite the fade out logic for fade in please let me know.

Variables defined at top:

int alpha = 0;
    bool backButtonClick = false;
    bool breakCheck = false;

Button's logic snippet:

        private void storyChooser_Click(object sender, EventArgs e)
        {

            switch (userChoice)
            {
                case Choice.Son:

                    transitions();


                     if (alpha == 0)
                    {
                        pictureBox1.Image = Properties.Resources.test;
                        timer1.Start();

                    }
                break;
            }

The timer:

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (backButtonClick == true)
            {
                timer1.Stop();
                alpha = 0;
                backButtonClick = false;
            }

            if (alpha++ < 40)
            {
                Image image = pictureBox1.Image;
                using (Graphics g = Graphics.FromImage(image))
                {
                    Pen pen = new Pen(Color.FromArgb(alpha, 255, 255, 255), image.Width);
                    g.DrawRectangle(pen, -1, -1, image.Width, image.Height);
                    g.Save();

                }
                pictureBox1.Image = image;
            }
            else
            {
                timer1.Stop();
            }

            if (alpha == 40 && breakCheck == false)
            {
                pictureBox1.Image = Properties.Resources.transitionTest;

                timer1.Start();

                while (alpha-- > 0)
                {
                    Image image = pictureBox1.Image;
                    using (Graphics g = Graphics.FromImage(image))
                    {
                        Pen pen = new Pen(Color.FromArgb(alpha, 255, 255, 255), image.Width);
                        g.DrawRectangle(pen, -1, -1, image.Width, image.Height);
                        g.Save();

                    }
                    pictureBox1.Image = image;
                    label1.Text = alpha.ToString();
                }
                breakCheck = true;
            }
            label1.Text = alpha.ToString();
        }

I'm running through the while loop, towards the bottom of the timer, without updating any of the graphics.

Thanks.

ZeroPhase
  • 649
  • 4
  • 21
  • `g.Save()` isn't needed. After changing `pictureBox1.Image`, be sure to call `pictureBox1.Invalidate()`. –  Feb 05 '13 at 22:11

4 Answers4

1

I think this might be because you are doing this all in the while loop, the ui doesn't get a chance to repaint itself before you change it.

You might want to do the subtraction part within the timer ticks too, rather than in one go.

Matt
  • 2,984
  • 1
  • 24
  • 31
1

It looks like your second fadein condition has a while loop in it.

That's going to make your control go from one side to the other before your next timer tick event.

I had to re-write your code so I could get a better feel for it, though.

Why are you using a PictureBox control if you are using Graphic to write directly to the screen?

Here is my horrible mangling of your code. I hope it doesn't offend.

I declared all of the variables up front so VS would not complain about bad definitions.

I also did not have a transitionTest image, so I defined a Properties_Resources_transitionTest for this.

int MAX = 40;
int alpha;
bool backButtonClick;
bool breakCheck;
Label label1;
Image Properties_Resources_transitionTest;
Image image;

Initialized stuff below and kicked it off. I don't know what your enumerated type means or that transition() method was for that you called.

private void storyChooser_Click(object sender, EventArgs e) {
  alpha = 0;
  backButtonClick = false;
  breakCheck = false;
  image = Properties_Resources_transitionTest;
  timer1.Start();
}

For the backButtonClick and breakCheck values, I put those inside a form's click event handler like so:

private void backButton_Click(object sender, EventArgs e) {
  backButtonClick = !backButtonClick;
}

private void break_Click(object sender, EventArgs e) {
  breakCheck = true;
  // easier to just write
  // timer1.Stop();
}

This Timer Tick event handler should take care of what you are trying to do. Notice the while loop has been removed, as well.

private void timer1_Tick(object sender, EventArgs e) {
  if (!breakCheck) {
    using (Pen p = new Pen(Color.FromArgb(alpha, 255, 255, 255), image.Width)) {
      using (Graphics g = Graphics.FromImage(image)) {
        g.DrawRectangle(p, 0, 0, image.Width, image.Height);
      }
    }
    if (backButtonClick) {
      alpha--;
      if (alpha == 0) {
        timer1.Stop();
      }
    } else {
      alpha++;
      if (alpha == MAX) {
        timer1.Stop();
      }
    }
  } else {
    timer1.Stop();
  }
  label1.Text = alpha.ToString();
}

UPDATE: Per question in the comment:

If backButtonClick is true, the alpha value will decrease by 1 each time the timer ticks and stop when alpha gets to zero.

If backButtonClick is false, alpha will increase until it reaches MAX, then stop the timer.

Since alpha controls your Pen color's Opacity, your image will appear to fade in and out, depending on what value you have backButtonClick set to.

I believe that is what you are after, but I could be wrong.

  • Will The draw function you posted also fade back up? And there is no need to worry about offending me. – ZeroPhase Feb 05 '13 at 23:49
  • Posted an Update to the solution to explain. It was too long to go here. –  Feb 06 '13 at 01:09
  • I believe what you have will work if I only have one image. After the first image fades I bring a second one in. Is there a method for setting the second images alpha at 0 upon load? – ZeroPhase Feb 06 '13 at 01:50
  • @p2code Oh, I know how to fade up. I just need to place 'g' in place of the pen. – ZeroPhase Feb 06 '13 at 02:09
  • Does that mean you got it figured out? After `alpha` fades all the way out, you can stop the timer or change the `image` to some other photo **and** change the value of `buttonBackClick` so that the fade goes the other way. Should I edit the code to show this or do you see what I'm saying? –  Feb 06 '13 at 14:16
0

I'm assuming you mean it skips the part after:

 if (alpha == 40 && breakCheck == false)

I think that doesn't execute because you stop incrementing alpha at a value of 39 because of this line:

if (alpha++ < 40)

If you change it to a less equal it should execute:

if (alpha++ <= 40)
Jos
  • 3
  • 1
  • I just tried your suggestion, and nothing changed. alpha still decrements during the while statement, but no graphical output occurs. – ZeroPhase Feb 05 '13 at 21:56
  • Stupid suggestion on my behalf, that check isnt the problem. I was too quick answering. – Jos Feb 05 '13 at 21:59
  • Does it make any difference if you don't switch the image in the second loop? (skipping pictureBox1.Image = Properties.Resources.transitionTest) – Jos Feb 05 '13 at 22:02
  • it does not make a difference. – ZeroPhase Feb 06 '13 at 02:25
-1

Why do people insist so much in winforms?

Look, you can do this in WPF with 20 lines of XAML and absolutely no C# code at all:

<Window x:Class="WpfApplication4.Window4"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window4" Height="300" Width="300">
    <Window.Resources>
        <Storyboard x:Key="FadeIn" TargetName="Red" Duration="00:00:05">
            <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1"/>
        </Storyboard>
        <Storyboard x:Key="FadeOut" TargetName="Blue" Duration="00:00:05">
            <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0"/>
        </Storyboard>
    </Window.Resources>
    <DockPanel>
        <Button DockPanel.Dock="Top"  HorizontalAlignment="Center" Content="Fade">
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.Click">
                    <EventTrigger.Actions>
                        <BeginStoryboard Storyboard="{StaticResource FadeIn}"/>
                        <BeginStoryboard Storyboard="{StaticResource FadeOut}"/>
                    </EventTrigger.Actions>
                </EventTrigger>
            </Button.Triggers>
        </Button>
        <Grid Margin="30">
            <Grid Background="Red" Opacity="0" x:Name="Red"/>
            <Grid Background="Blue" x:Name="Blue"/>
        </Grid>
    </DockPanel>
</Window>

Code Behind:

using System.Windows;

namespace WpfApplication4
{
    public partial class Window4 : Window
    {
        public Window4()
        {
            InitializeComponent();
        }
    }
}

Just copy and paste my code in a file -> new project -> WPF application and see the results for yourself.

These are grids with a solid color background. You could replace the <Grid/>s by <Image/>s or anything you wish.

Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • 2
    A `WPF` solution won't really help his `WinForm` question though, unless I'm missing something. –  Feb 05 '13 at 22:13
  • 1
    It did [here](http://stackoverflow.com/questions/14565773/improving-winforms-performance-with-large-number-of-controls/14566539#14566539) and [here](http://stackoverflow.com/questions/14710117/updating-ui-in-c-sharp-using-timer/14711744#14711744), where they realized that winforms is useless and dropped it altogether in favor of WPF. – Federico Berasategui Feb 05 '13 at 22:16
  • Also, if the OP decides not to go up, he can still use an `ElementHost` in winforms and do the animations in WPF to simplify his life, instead of having to deal with all that code in there. – Federico Berasategui Feb 05 '13 at 22:17
  • 2
    People use Winforms because they don't understand how WPF objects relate to code, or for that matter what parts of the XAML are declarative descriptions of immutable aspects and what parts are imperative descriptions that modify mutable aspects? None of the tutorials I've seen have explained it in a manner I could understand, and I'm sure I'm not alone. – supercat Feb 05 '13 at 22:26
  • @user2028236 Sorry, I forgot to post the code behind. I corrected my post. – Federico Berasategui Feb 05 '13 at 22:36
  • @supercat Yeah, I'm pretty sure that the XAML I posted here is not understandable by a developer, whereas the gargantuan amount of code required to do the same in winforms is somehow more clear. – Federico Berasategui Feb 05 '13 at 22:37
  • I almost have my code working, but now am stuck looping through the timer infinitely. – ZeroPhase Feb 05 '13 at 22:47
  • @user2028236 They shouldn't. MSFT just released a whole new technology last year. It's called WinRT. Guess what? It's XAML-based, not winforms-based. Wake up. As an aside, just give another try to my code, because I forgot to post the code behind, and compare the results. – Federico Berasategui Feb 05 '13 at 22:50
  • @supercat people use winforms because they kept the 80's procedural mindset. I can't understand what you're saying about "immutable aspects" and all that stuff. Winforms is useless. Period. You cannot give me a single use case where it outperforms WPF in performance, development time, scalability. – Federico Berasategui Feb 05 '13 at 22:54
  • @HighCore: I've tried creating a couple simple apps in WPF and I couldn't figure out the relationship between the controls and any sorts of objects my code could work with. Maybe I just haven't seen the right tutorials, but I can at least understand Winforms. The ListBox may be crummy, but it's pretty straightforward: all `theBox.Items.Add()` to put things in it. None of the Winforms tutorials I've seen show anything nearly as straightforward. Creating a custom control is also easy in WinForms--just define an imperative `Paint` method. Not clue how to do that in WPF. – supercat Feb 05 '13 at 23:45
  • @supercat the WPF `ListBox` also supports `theBox.Items.Add()`, but that's not the `only` way to do it. Since data binding is tightly integrated in the framework, it's usually better to have a more elevated mindset to work with it. I possitively agree that the learning curve `might` be steeper, because a more powerful framework has more classes and concepts and ways to work with. Pretty much like the difference between .Net 2.0 web services and WCF. WPF allows for the creation of XAML-only zero-code UIs, by the use of Bindings and simple POCO classes with properties. Winforms doesn't have that – Federico Berasategui Feb 06 '13 at 02:05
  • @Supercat But that's no excuse for a developer not to learn the current technology. Its like saying that you stick with VB6 because .Net has "too much classes" or "it's too complicated with abstract classes, interfaces and generics". WPF allows for Styling and Templating of controls, Styles are conceptually the same as CSS, and Templates are definitions of the visual content of controls. It's not really hard to understand. You don't need `OnPaint()` in WPF because you can define a `ControlTemplate` for any control and inside the template you can put whatever content you want, declaratively. – Federico Berasategui Feb 06 '13 at 02:10
  • @Supercat in the end you realize WPF is actually simpler because you rarely have to manipulate visual elements in code. For instance, instead of manipulating a `CheckBox` in code, you have some `public bool` Property somewhere in a `ViewModel` and work against that, and the Bindings keep the `CheckBox.IsChecked` property in Sync with the bool value. You don't have to worry about how many controls in the UI actually operate against that bool property. Please take a look at [this](http://stackoverflow.com/questions/14381402/wpf-programming-methodology/14382137#14382137) explanation. – Federico Berasategui Feb 06 '13 at 02:20
  • @HighCore: You asked why people use Winforms. WPF may be better in many ways, but it does have a steep learning curve. Suppose one wants to have a control that shows a graph of y=x^p, for x and y in the range 0 to 1, and a p value set by a slider. With Winforms, simply have the slider set the p property on the control which in turn invalidates it; the paint method will then redraw it. How would one do something like that in wpf? – supercat Feb 06 '13 at 05:24
  • @supercat you can actually draw `PolyLine`s using X,Y coordinates to a `Canvas` in WPF. You can create a custom control that has X and Y properties, and since WPF properties are DependencyProperties, you can determine (in the very declaration) whether these properties [Affect Measure](http://msdn.microsoft.com/en-us/library/system.windows.frameworkpropertymetadata.affectsmeasure.aspx) or [Affect Render](http://msdn.microsoft.com/en-us/library/system.windows.frameworkpropertymetadata.affectsrender.aspx). You don't need `Invalidate` because WPF does it by itself when such properties are modified – Federico Berasategui Feb 06 '13 at 12:34
  • @supercat Also, you don't even need to write code to tie 2 properties of different controls together, because that can be performed with a simple `{Binding}` – Federico Berasategui Feb 06 '13 at 12:37
  • @supercat I made an example of a a line controlled by sliders. It doesn't perform any calculations, but that could easily be added with the use of [Value Converters](http://wpftutorial.net/ValueConverters.html), where you can write any code to manipulate the source value of a Binding before it impacts the target, and vice versa. Look http://pastebin.com/p03xviFT. Its CODELESS, meaning it only took 10 lines of XAML to perform that and no C# at all. Also, if you resize the window, you realize that this is Resolution Independent, meaning it scales according to the container (window) size. – Federico Berasategui Feb 06 '13 at 14:28
  • @HighCore: I guess the intended point of my example is that I'm not clear on how one would deal with situations where the stuff to be drawn depends in some "complicated" way upon other factors. If the window is 32 pixels wide, the WinForms approach would compute 32 values of x^P; if it's 2048 pixels wide, it would compute 2048 values. Would the WPF approach be to create some number of line segments and hope it's reasonable for the display size? Also, in WPF is there any good way of taking pixel-level control? I can show 4096 hex bytes legibly in an 800x400 window in Winforms. Can WPF? – supercat Feb 06 '13 at 17:24
  • @supercat there's way for everything you can do in winforms. WPF > winforms in every way. You can use a `DrawingVisual` in WPF to do per pixel stuff, however in most cases it's not needed. Did you run the example I linked to? WPF's layout system allows for resolution independence, and you don't need to deal with weird calculations of width and height. Also, there's the `ViewBox` which can stretch its contents to fit the available space, either retaining the aspect ratio or not. – Federico Berasategui Feb 06 '13 at 17:38
  • @supercat also, there's MVVM, where if `the stuff to be drawn depends in some "complicated" way upon other factors`, you can always have a ViewModel which does all the complex stuff and expose simple properties for Visual Elements to bind to. – Federico Berasategui Feb 06 '13 at 17:41
  • Perhaps we can move to chat? I didn't run the sample, but I looked at it. The number of parameters required to define the line's location was constant (four). If the number of points to define a curve, or the number of objects to be drawn, should vary with resolution, should one destroy and recreate a list of points/drawing objects each time the window size changes enough that the existing list is no longer optimal, or somehow bind an `IEnumerable` or `IEnumerable` which could get called when rendering the screen, or what? – supercat Feb 06 '13 at 18:04
  • @supercat http://pastebin.com/sV5TEkAH. My version of 4096 hex bytes in an 800x400 space. 20 Lines of XAML and 6 lines of C#. – Federico Berasategui Feb 06 '13 at 18:07
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/24055/discussion-between-highcore-and-supercat) – Federico Berasategui Feb 06 '13 at 18:16