Прокрутка колесиком мыши в панели с динамически добавленными элементами управления картинкой? - PullRequest
5 голосов
/ 02 декабря 2009

Я динамически добавил 20 панелей изображений на панель и хотел бы видеть прокрутку панели при использовании колесика мыши. Чтобы реализовать это, я попытался установить автопрокрутку на true на панели управления. Вот код Для меня как целое число = 1 до 20:

        Dim b As New PictureBox()
        b.Image = Nothing
        b.BorderStyle = BorderStyle.FixedSingle
        b.Text = i.ToString()
        b.Size = New Size(60, 40)
        b.Location = New Point(0, (i * b.Height) - b.Height)
        b.Parent = Panel1
        Panel1.Controls.Add(b)
    Next

Я сделал то же самое с кнопочным управлением, и оно работает просто отлично. Для меня как целое число = 1 до 100:

        Dim b As New Button()

        b.Text = i.ToString()
        b.Size = New Size(60, 40)
        b.Location = New Point(0, (i * b.Height) - b.Height)
        b.Parent = Panel1
        Panel1.Controls.Add(b)
    Next

Это работает для элемента управления «кнопка», но не для элементов управления «изображение» или «ярлык»? Как реализовать эффект прокрутки с помощью колесика мыши?

Ответы [ 2 ]

6 голосов
/ 02 декабря 2009

Панель прокручивается колесом мыши, когда оно или элемент управления внутри него имеют фокус. Проблема, с которой вы сталкиваетесь, заключается в том, что ни PictureBox, ни панель не получают фокус при нажатии на нее. Если вы наберете select() на панели, вы увидите, что колесо мыши снова начинает работать.

Одним из возможных решений было бы выбрать панель всякий раз, когда курсор мыши вводит ее, путем обработки события Control.MouseEnter:

void panel1_MouseEnter(object sender, EventArgs e)
{
    panel1.select();
}
3 голосов
/ 02 декабря 2009

"cwick" совершенно прав, Windows отправляет уведомление WM_MOUSWHEEL в окно, которое имеет фокус. Это работает, когда вы помещаете кнопку в панель, потому что она может получить фокус. Следующее, что происходит, - это то, что Windows продолжает искать родительский элемент управления, чтобы принять сообщение. Кнопка не заботится об этом, это Parent - это панель, и она с радостью прокрутит и поглотит сообщение.

Помимо врачевания со способностью дочерних элементов управления фокусироваться (вам придется переопределить их и вызвать SetStyle (ControlStyles.Selectable)), вы могли бы рассмотреть возможность изменения способа обработки этого сообщения. Многие коммерческие приложения, по-видимому, не имеют этой проблемы (браузеры, приложения Office), потому что у них всего несколько окон. В приложениях WF обычно их много, по одному на каждый элемент управления. Сделайте это, обработав сообщение на ранней стадии, прежде чем оно будет отправлено целевому элементу управления. Интерфейс IMessageFilter позволяет это. Этот пример кода прокручивает элемент управления под мышью, а не элемент управления с фокусом:

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication1 {
  public partial class Form1 : Form, IMessageFilter {
    public Form1() {
      InitializeComponent();
      Application.AddMessageFilter(this);
    }

    public bool PreFilterMessage(ref Message m) {
      if (m.Msg == 0x20a) {
        // WM_MOUSEWHEEL, find the control at screen position m.LParam
        Point pos = new Point(m.LParam.ToInt32());
        IntPtr hWnd = WindowFromPoint(pos);
        if (hWnd != IntPtr.Zero && hWnd != m.HWnd && Control.FromHandle(hWnd) != null) {
          SendMessage(hWnd, m.Msg, m.WParam, m.LParam);
          return true;
        }
      }
      return false;
    }

    // P/Invoke declarations
    [DllImport("user32.dll")]
    private static extern IntPtr WindowFromPoint(Point pt);
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
  }
}

Помните, что этот код активен для любого окна в вашем приложении. Убедитесь, что вы попробуете это и убедитесь, что это не слишком запутает пользователя.

...