Scrollbars maxvalue is too high

P

Pauli Østerø

I have a serious problem. I have made an Control which draws a blueprint
of a building and a related SpotMatrix. I have made it possible to zoom
in on the blueprint and scroll around if the size esceeds the size of the
control.

But there is something weird happening. Thus more i zoom ind, the bigger
gets the miscalculation of the scrollbars maxvalues. That results in that
i'm able to scroll to far to the right and down.

My ZoomLevel property is this:

public int ZoomLevel
{
set
{
this.zoomPercentage = value;

this.blueprintZoomHeight = (int)(this.blueprint.Height *
value/100);
this.blueprintZoomWidth = (int)(this.blueprint.Width *
value/100);

this.displayScrollBars();
this.setScrollBarValues();
this.Invalidate();
}
}

And i calculates the maxvalues of my scrollbars like this.

private void setScrollBarValues()
{
//
//TODO: There is a bug wich gives the scrollbars increasingly
higher maxvalues than they should
//

this.vScrollBar.Minimum = this.hScrollBar.Minimum = 0;

// If the offset does not make the Maximum less than zero,
set its value.
if( (this.blueprintZoomWidth - this.rectToDrawIn.Width) > 0)
{
this.hScrollBar.Maximum = this.blueprintZoomWidth - (int)
this.rectToDrawIn.Width;
}
this.hScrollBar.LargeChange = this.hScrollBar.Maximum / 10;
this.hScrollBar.SmallChange = this.hScrollBar.Maximum / 20;
this.hScrollBar.Maximum += this.hScrollBar.LargeChange;

// If the offset does not make the Maximum less than zero,
set its value.
if( (this.blueprintZoomHeight - this.rectToDrawIn.Height) >
0)
{
this.vScrollBar.Maximum = this.blueprintZoomHeight -
(int)this.rectToDrawIn.Height;
}

this.vScrollBar.LargeChange = this.vScrollBar.Maximum / 10;
this.vScrollBar.SmallChange = this.vScrollBar.Maximum / 20;
this.vScrollBar.Maximum += this.vScrollBar.LargeChange;
}


Is there anyone who can see any errors or mistakes in my code? I guess
i've been struggling with it for so long that i cant see the forest
because of all the trees.
 
D

Dan Bass

As a suggestion, never write this:
int x = 1234;
int y = x / 30 * 100;

Rather write this:
y = (double)x / (double)30 * (double)100;


the differences as a result of rounding errors are quite substantial. See
the example here:

using System;

namespace RoundOff
{
class IntRounding
{
[STAThread]
static void Main()
{

int x = 1234;
int y = x / 30 * 100;

Console.WriteLine ( "int round off = " + y.ToString() );

y = (int)( (double)x / (double)30 * (double)100);

Console.WriteLine ( "double round off = " + y.ToString() );
}
}
}


This produces the following output:

int round off = 4100
double round off = 4113


I suspect this is where your problem lies.

Hope that helps.

Daniel.
 
P

Pauli Østerø

As a suggestion, never write this:
int x = 1234;
int y = x / 30 * 100;

Rather write this:
y = (double)x / (double)30 * (double)100;


the differences as a result of rounding errors are quite substantial.

Yeah... i've thought of that, but it don't seem to make a big difference.
Its maybe a misunderstanding from my point of view of what the Maxvalue
of my scrollbars mean. When i have zoomed my picture to 200 % i'm able to
scroll 1 time to far to the right and down. It's hard to describe but
maybe this little ascii-drawing can.

This is my picture showed 100% in my control.

----------
| |
| |
| |
| |
|---------

When i zoom to 200 % only a little part of it is shown:

----------
|**** |
|* * |
|**** |
| |
|---------

And it should only be aply to move the view-area to the edge of the
original picture. But for some odd reason im able to scroll this far:

----------
| |****
| |* *
| |****
| |
|---------

When zoomed to 200 % i would think that my hScrollBar's maxvalue should
be the remaining distance from the right edge of my view area to the
right edge of my orignal picture

----------
|****<-->|
|* * |
|**** |
| |
|---------

But is this a misunderstanding?
 
D

Dan Bass

Surely if the image can be seen entirely in the view then the scroll bars
both have a maximum of 0? IE you can't scroll anywhere... From what I can
tell, you're not setting the max if the "image" width is less than the
viewing area width...

Try this:
private void setScrollBarValues()
{
this.vScrollBar.Minimum = this.hScrollBar.Minimum = 0;

this.hScrollBar.Maximum = Math.Max(0,this.blueprintZoomWidth -
(int)this.rectToDrawIn.Width);
this.hScrollBar.LargeChange = this.hScrollBar.Maximum / 10;
this.hScrollBar.SmallChange = this.hScrollBar.Maximum / 20;
this.hScrollBar.Maximum += this.hScrollBar.LargeChange;

this.vScrollBar.Maximum = Math.Max(0,this.blueprintZoomHeight -
(int)this.rectToDrawIn.Height);
this.vScrollBar.LargeChange = this.vScrollBar.Maximum / 10;
this.vScrollBar.SmallChange = this.vScrollBar.Maximum / 20;
this.vScrollBar.Maximum += this.vScrollBar.LargeChange;
}
 
P

Pauli Østerø

Surely if the image can be seen entirely in the view then the scroll
bars both have a maximum of 0? IE you can't scroll anywhere... From
what I can tell, you're not setting the max if the "image" width is
less than the viewing area width...

i have this if-statement

if( (this.blueprintZoomWidth - this.rectToDrawIn.Width) > 0)
{
this.hScrollBar.Maximum = this.blueprintZoomWidth - (int)
this.rectToDrawIn.Width;
}

saying, that the maxvalue will only be set if the zoomed image exceeds
the size of my viewing area.

Right before i call my setScrollBarValues-method i check whether the bars
should be displayed or not, so if the viewing area is able to show my
entire blueprint the scrollbars arent shown.

I have tried different things but just can't get it right. I've boiled my
two method (displayScrollBars and setScrollbarValues) into one, but the
problem is still the same :( I guess i have to go back to the books and
find out how the value of scrollbars really works.

private void setScrollBarValues()
{
//
//TODO: There is a bug wich gives the scrollbars
increasingly higher maxvalues than they should
//

// If the image is wider than the Control, show the
HScrollBar.
if (this.rectToDrawIn.Width < this.blueprintZoomWidth)
{
this.hScrollBar.Maximum = this.blueprintZoomWidth
- this.rectToDrawIn.Width;

this.hScrollBar.LargeChange =
this.hScrollBar.Maximum / 10;
this.hScrollBar.SmallChange =
this.hScrollBar.Maximum / 20;
this.hScrollBar.Maximum +=
this.hScrollBar.LargeChange;

this.hScrollBar.Enabled = true;
}
else
{
this.hScrollBar.Enabled = false;
}

// If the image is taller than the Control, show the
VScrollBar.
if (this.rectToDrawIn.Height <
this.blueprintZoomHeight)
{
this.vScrollBar.Maximum =
this.blueprintZoomHeight - this.rectToDrawIn.Height;

this.vScrollBar.LargeChange =
this.vScrollBar.Maximum / 10;
this.vScrollBar.SmallChange =
this.vScrollBar.Maximum / 20;
this.vScrollBar.Maximum +=
this.vScrollBar.LargeChange;

this.vScrollBar.Enabled = true;
}
else
{
this.vScrollBar.Enabled = false;
}
}

my method to calculate what area to paint from looks like this (i've
changed my zoomPercentage so its a decimal in the format (100% = 1.0, 50%
= 0.5). This function is called everytime the scrollbar is scrolled or
the ZoomLevel is changed. It's gotta be either in this method or in the
one above the error is in.

private void createAreaToPaintFrom()
{
rectToDrawFrom = new Rectangle(hScrollBar.Value,
vScrollBar.Value,
(int)(this.rectToDrawIn.Width /
this.zoomPercentage),
(int)(this.rectToDrawIn.Height /
this.zoomPercentage));
}
 
R

Rachel Suddeth

Not sure, but I don't think you are supposed to have to add LargeChange to
the Maximum.
You might have to add the width of the other dimension's scrollbar if it is
visible.

-Rachel
 
D

Dan Bass

i have this if-statement
if( (this.blueprintZoomWidth - this.rectToDrawIn.Width) > 0)
{
this.hScrollBar.Maximum = this.blueprintZoomWidth - (int)
this.rectToDrawIn.Width;
}

saying, that the maxvalue will only be set if the zoomed image exceeds
the size of my viewing area.

This will not work based on the fact that there is already a value of
Maximum in the scroll bar. Hence my suggestion of rather using Math.Max ( 0,
.... ). This insures you assign a value to your scroll bars based on your new
zoom.

Right before i call my setScrollBarValues-method i check whether the bars
should be displayed or not, so if the viewing area is able to show my
entire blueprint the scrollbars arent shown.

That's fair enough.
 
P

Pauli Østerø

I got it to work now :) The problem was that i always used my ViewArea as
reference for calculating how much i needed to scroll and not my size of
the original picture.

This code works :)

private void setScrollBarValues()
{
Rectangle rectToDrawFrom =
this.diagramPainter.RectangleToDrawFrom;

// If the image is wider than the Control, show the
HScrollBar.
if (this.diagramPainter.HorizontalScrollNeeded)
{
this.hScrollBar.Maximum =
this.diagramPainter.BlueprintSize.Width - rectToDrawFrom.Width;

this.hScrollBar.LargeChange =
this.hScrollBar.Maximum / 10;
this.hScrollBar.SmallChange =
this.hScrollBar.Maximum / 20;
this.hScrollBar.Maximum +=
this.hScrollBar.LargeChange;

this.hScrollBar.Enabled = true;
}
else
{
this.hScrollBar.Enabled = false;
}

// If the image is taller than the Control, show the
VScrollBar.
if (this.diagramPainter.VerticalScrollNeeded)
{
this.vScrollBar.Maximum =
this.diagramPainter.BlueprintSize.Height - rectToDrawFrom.Height;

this.vScrollBar.LargeChange =
this.vScrollBar.Maximum / 10;
this.vScrollBar.SmallChange =
this.vScrollBar.Maximum / 20;
this.vScrollBar.Maximum +=
this.vScrollBar.LargeChange;

this.vScrollBar.Enabled = true;
}
else
{
this.vScrollBar.Enabled = false;
}
}

private void createRectToPaintFrom()
{
this.diagramPainter.RectangleToDrawFrom = new Rectangle
(
hScrollBar.Value, vScrollBar.Value,
(int)(this.diagramPainter.BlueprintSize.Width /
this.diagramPainter.ZoomLevel),
(int)(this.diagramPainter.BlueprintSize.Height /
this.diagramPainter.ZoomLevel));
}
 
P

Pauli Østerø

Not sure, but I don't think you are supposed to have to add
LargeChange to the Maximum.
You might have to add the width of the other dimension's scrollbar if
it is visible.

The extra value to be added to maxvalue is indeed needed. As you see in my
code i'm adding both the width and the largechange to my maximum.

View my other reply to Dan Bass for the working code.

/Pauli
 
Top