c # .NET 2.0 масштаб-полоса прокрутки - PullRequest
3 голосов
/ 08 июня 2011

Я ищу элемент управления, который позволяет пользователям одновременно масштабировать и прокручивать.По сути, это должно быть что-то вроде Sony Sound Forge, см. Нижнюю часть этого скриншота: enter image description here

Он выглядит и ведет себя как обычная полоса прокрутки, с добавлением, что вы можете перетаскивать края влево ивправо, увеличивая / уменьшая график.Даже если пользователю будут предложены альтернативные способы увеличения и прокрутки (например, путем перетаскивания области на самой диаграмме), я все равно думаю, что такой компонент полезен, потому что он дает пользователю прямую визуальную обратную связь о положении в данных иколичество примененного масштабирования.

Существует ли такой компонент или мне нужно создать его самостоятельно?Любая помощь приветствуется.

1 Ответ

2 голосов
/ 05 июля 2011

Я думаю, что это очень специфический контроль, и я не думаю, что он существует.Также я думаю, что будет быстрее создать его самостоятельно, чем искать его или даже ждать, когда кто-то ответит на этот вопрос.

Чтобы нарисовать пользовательские кнопки, как в Sound Forge , вы можете использовать WinAPIfunction DrawThemeBackground.

Я приведу небольшой пример:

enter image description here

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 для сигнатур функций.

EDIT

Более лучшим решением является использование 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));
    }
}

EDIT 2

Учитывая ваши комментарии, я сделал новую попытку воссоздать этот пользовательский элемент управления.Основная идея заключалась в том, чтобы использовать стандартный ScrollBar и поместить над ним маркеры масштабирования (два элемента управления Panel).Это выглядит легко с первого взгляда.Но объединить эти компоненты вместе было сложнее, чем я думал.

Основная проблема заключается в том, что сложно изменить поведение системного элемента управления ScrollBar.Я обнаружил, что он не позволяет обрабатывать некоторые события в очереди сообщений Windows, которые я хотел переопределить.Например, событие MouseUp и некоторые другие.

В конце я думаю, что единственный правильный путь - это воссоздать собственную копию элемента управления ScrollBar с нуля, в которой не будет этих ограничений.Из-за этого изначально я пошел по неверному пути и, к сожалению, не решил вашу задачу.

В любом случае, здесь мои текущие результаты (полное решение): scrollbar-with-zoom-3.zip

...