【问题标题】:c# .NET 2.0 zoom-scroll barc# .NET 2.0 缩放滚动条
【发布时间】:2011-09-10 16:37:56
【问题描述】:

我正在寻找一种允许用户同时缩放和滚动的控件。它基本上需要像 Sony Sound Forge 那样,见截图底部:

它的外观和行为类似于普通滚动条,此外,您可以左右拖动边缘来放大/缩小图表。即使为用户提供了放大和滚动的替代方法(例如,通过拖动图表本身的区域),我仍然认为这样的组件很有用,因为它为用户提供了数据中位置的直接视觉反馈,并且已应用的缩放量。

这样的组件是否存在或者我需要自己创建它?欢迎任何帮助。

【问题讨论】:

  • 您在该容器中使用哪些控件?
  • 我打算使用图形显示,很像上面的截图。这是否回答你的问题?因为我认为这无关紧要。例如,每次用户缩放或滚动时,缩放滚动条必须简单地给出 2 个介于 0 和 1 之间的浮点值。这些值表示条的开始和结束位置。 (上面的截图是 Sony Sound Forge,索尼的音频编辑工具,不是我自己的软件)
  • 我认为你可以通过你的组件解决这个问题,我认为每次缩放都必须放大你的精度。
  • @lazycider:我不认为我们在这里处于同一波长,至少我根本不理解你的答案。我正在寻找屏幕截图中的 UI 控件。这种控制背后的逻辑当然不是火箭科学。正如我上面所描述的,每次用户操作控件时它应该只返回 2 个值。我只是想知道这样的 UI 组件是否存在。我当然可以自己创建一个,但要为其提供一致的 Windows 外观和感觉,这将是一项相当大的工作。

标签: c# scroll c#-2.0 zooming charts


【解决方案1】:

我认为这是非常具体的控制,我认为它不存在。另外我认为自己创建它会比搜索它甚至等待有人回答这个问题时更快。

要在 Sound Forge 中绘制自定义按钮,您可以使用 WinAPI 函数DrawThemeBackground

我做一个简短的例子:

public partial class Form1 : Form
{
    readonly Int32 ScrollBarWidth;
    readonly Int32 ScrollBarHeight;



    public Form1()
    {
        InitializeComponent();

        ScrollBarWidth  = GetSystemMetrics(SM_CYVSCROLL);
        ScrollBarHeight = GetSystemMetrics(SM_CYHSCROLL);
    }



    private void panel1_Paint(object sender, PaintEventArgs e)
    {
        Int32 ZoomMarkerSize = 6;

        Graphics G      = e.Graphics;
        Int32 SBWidth   = ScrollBarWidth;
        Int32 SBHeight  = ScrollBarHeight;

        DrawCustomScrollButton(G, 0, 0, SBWidth, SBHeight, Resources.Plus,
            (int) SCROLLBARSTYLESTATES.SCRBS_NORMAL);
        DrawCustomScrollButton(G, SBWidth, 0, ZoomMarkerSize, SBHeight, null,
            (int) SCROLLBARSTYLESTATES.SCRBS_NORMAL);
        DrawCustomScrollButton(G, SBWidth + ZoomMarkerSize, 0, SBWidth, SBHeight, Resources.Minus,
            (int) SCROLLBARSTYLESTATES.SCRBS_HOT);
    }



    public void DrawCustomScrollButton (Graphics aG, Int32 aX, Int32 aY, Int32 aWidth, Int32 aHeight,
        Image aImage, Int32 aState)
    {
        RECT R = new RECT () { left = aX, top = aY, right = aX + aWidth, bottom = aY + aHeight };
        RECT NotUsed = R;

        IntPtr ThemeHandle  = OpenThemeData(this.Handle, "SCROLLBAR");
        IntPtr HDC          = aG.GetHdc();

        DrawThemeBackground
        (
            ThemeHandle, HDC,
            (int) SCROLLBARPARTS.SBP_THUMBBTNHORZ,
            aState,
            ref R, ref NotUsed
        );

        aG.ReleaseHdc(HDC);
        CloseThemeData(ThemeHandle);

        if (aImage != null)
        {
            aG.DrawImage(aImage,
                aX + ((ScrollBarHeight - aImage.Width   ) / 2),
                aY + ((ScrollBarHeight - aImage.Height  ) / 2));
        }
    }



    public struct RECT
    {
        public Int32 left; 
        public Int32 top; 
        public Int32 right; 
        public Int32 bottom; 
    }

    [DllImport("user32.dll")]
    public static extern int GetSystemMetrics(int smIndex);

    [DllImport("uxtheme.dll", ExactSpelling=true)]
    public extern static Int32 DrawThemeBackground(IntPtr hTheme, IntPtr hdc, int iPartId,
       int iStateId, ref RECT pRect, ref RECT pClipRect);

    [DllImport("uxtheme.dll", ExactSpelling=true, CharSet=CharSet.Unicode)]
    public static extern IntPtr OpenThemeData(IntPtr hWnd, String classList);

    [DllImport("uxtheme.dll", ExactSpelling=true)]
    public extern static Int32 CloseThemeData(IntPtr hTheme);

    public int SM_CYHSCROLL = 3;
    public int SM_CYVSCROLL = 20;

    public int SBP_ARROWBTN = 1;

    public int ABS_UPNORMAL = 1;
    public int ABS_UPHOT = 2;
    public int ABS_UPHOVER = 17;

    public enum ARROWBTNSTATES {
        ABS_UPNORMAL = 1,
        ABS_UPHOT = 2,
        ABS_UPPRESSED = 3,
        ABS_UPDISABLED = 4,
        ABS_DOWNNORMAL = 5,
        ABS_DOWNHOT = 6,
        ABS_DOWNPRESSED = 7,
        ABS_DOWNDISABLED = 8,
        ABS_LEFTNORMAL = 9,
        ABS_LEFTHOT = 10,
        ABS_LEFTPRESSED = 11,
        ABS_LEFTDISABLED = 12,
        ABS_RIGHTNORMAL = 13,
        ABS_RIGHTHOT = 14,
        ABS_RIGHTPRESSED = 15,
        ABS_RIGHTDISABLED = 16,
        ABS_UPHOVER = 17,
        ABS_DOWNHOVER = 18,
        ABS_LEFTHOVER = 19,
        ABS_RIGHTHOVER = 20,
    };

    public enum SCROLLBARSTYLESTATES {
        SCRBS_NORMAL = 1,
        SCRBS_HOT = 2,
        SCRBS_PRESSED = 3,
        SCRBS_DISABLED = 4,
        SCRBS_HOVER = 5,
    };

    public enum SCROLLBARPARTS {
        SBP_ARROWBTN = 1,
        SBP_THUMBBTNHORZ = 2,
        SBP_THUMBBTNVERT = 3,
        SBP_LOWERTRACKHORZ = 4,
        SBP_UPPERTRACKHORZ = 5,
        SBP_LOWERTRACKVERT = 6,
        SBP_UPPERTRACKVERT = 7,
        SBP_GRIPPERHORZ = 8,
        SBP_GRIPPERVERT = 9,
        SBP_SIZEBOX = 10,
    };
}

这里是表单源文件和两个用于资源的测试 PNG 图像:
scrollbar-with-zoom-example.zip

查看 MSDN 以获取有关此 API 的更多信息,并查看 PINVOKE.NET 站点以获取函数签名。

编辑

更好的解决方案是使用VisualStyleRenderer 类。对不起,第一个复杂的例子。我以前不知道那门课。所以我的DrawCustomScrollButton函数应该被替换:

public void DrawCustomScrollButton (Graphics aG, Int32 aX, Int32 aY, Int32 aWidth, Int32 aHeight,
    Image aImage, Int32 aState)
{
    Rectangle R = new Rectangle(aX, aY, aX + aWidth, aY + aHeight);

    VisualStyleRenderer Renderer = new VisualStyleRenderer
    (
        VisualStyleElement.ScrollBar.ThumbButtonHorizontal.Normal
    );

    Renderer.DrawBackground(aG, R);

    if (aImage != null)
    {
        aG.DrawImage(aImage,
            aX + ((ScrollBarHeight - aImage.Width   ) / 2),
            aY + ((ScrollBarHeight - aImage.Height  ) / 2));
    }
}

编辑 2

考虑到您的 cmets,我重新尝试重新创建此自定义控件。主要思想是使用标准 ScrollBar 并在其上方放置缩放标记(两个面板控件)。乍一看很容易。但是将这些组件组合在一起比我想象的要困难。

主要问题是难以改变系统 ScrollBar 控件的行为。我发现它不允许处理我想要覆盖的 Windows 消息队列中的某些事件。例如 MouseUp 事件和其他一些事件。

最后,我认为唯一正确的方法是从头开始重新创建自己的 ScrollBar 控件副本,其中不会有这些约束。正因为如此,一开始我走错了路,很遗憾没有解决你的任务。

无论如何,我目前的结果(完整解决方案): scrollbar-with-zoom-3.zip

【讨论】:

  • 我不介意 + 和 - 按钮。事实上,我会很高兴有 2 个按钮,只是将 + 和 - 作为文本放在它们上面。它们可以与滚动条集成到自定义控件中。但这不是主要问题。主要问题是滚动条本身必须使用户能够允许缩放和滚动。滚动将像任何普通滚动条一样完成,缩放将通过将条的一侧(或某些人称之为拇指)拖离条的另一侧更近或更远来完成。
  • 如果您仔细查看示例,您会发现该条的每一侧都有 2 个抓手,而不是像普通滚动条那样在中间只有一个。
  • 现在我明白了。过去我使用过这个程序的旧版本,并没有完全理解你的问题。可悲的是,您没有在屏幕截图上做您需要的标记。我今天还安装了 Sound Forge 的试用版,并看到了新的滚动条是如何工作的。因此,稍后我将有时间尝试为您的问题找到更正确的答案。如果我能成功,我会更新。
  • 今天我做了一个新的例子,但它没有完成并且有一些错误。如果您想在这里查看我当前的结果,我的解决方案:scrollbar-with-zoom-2.zip
  • 德米特里,这看起来非常漂亮,正是我想要的。
猜你喜欢
  • 1970-01-01
  • 2015-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多