如何让智能手机像滚动的一个WinForms触摸屏应用(滚动面板) [英] how to get smartphone like scrolling for a winforms touchscreen app ( scrolling panel )

查看:215
本文介绍了如何让智能手机像滚动的一个WinForms触摸屏应用(滚动面板)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在网上淘到的文章后,我想出了这样的设计对于需要像智能手机滚动一个WinForms基于触摸屏的应用程序。该应用程序本身将在平板电脑上的笔记本电脑或台式机的触摸屏运行。




  • 我把一切我想在面板上滚动。

  • 自动滚屏设置为true(这将显示滚动条)

  • 现在,把这个整个面板一组框

  • <李里>收缩组框,直到滚动条隐藏的(视觉上隐藏的,不可见= FALSE)


现在最有趣的部分,我停留在。我想我必须处理MouseDown,鼠标松开&安培;鼠标移动面板上设置autoscrollposition这样,当有人触摸面板和拖动,但它确实是神奇卷轴。填写代码如下方法存根的几行字,请帮助。在autoscrollposition的 MSDN文档是非常混乱,因为它返回负数电话号码,但需要被设置为正的有ABS,什么不是。

 点mouseDownPoint; 
点mouseUpPoint;
点mouseDragPoint;
私人无效myPanel_MouseDown(对象发件人,MouseEventArgs E)
{
this.mouseDownPoint = e.Location;
Console.WriteLine(鼠标下来{0},e.location);
}

私人无效myPanel_MouseUp(对象发件人,MouseEventArgs E)
{
this.mouseUpPoint = e.Location;
this.mouseDownPoint =新点(); //将为为IsEmpty检查
Console.WriteLine(鼠标向上在{0},e.location)设置;
}

私人无效myPanel_MouseMove(对象发件人,MouseEventArgs E)
{
Console.WriteLine(鼠标在{0},e.location);
如果(mouseDownPoint.IsEmpty())//手指松开触摸屏
的回报;
myPanel.Autocrollposition =?
}

感谢您



//更新 - 下面我有试错的工作和放大器;测试的代码。 (不是重构)。如果有人有一个更好的解决方案,请上传



 点mouseDownPoint。 
私人无效innerpanel_MouseDown(对象发件人,MouseEventArgs E)
{
如果(e.Button == MouseButtons.Left)
this.mouseDownPoint = e.Location;
}

私人无效innerpanel_MouseMove(对象发件人,MouseEventArgs E)
{
如果(e.Button = MouseButtons.Left!)
的回报;
如果((mouseDownPoint.X == e.Location.X)及及(mouseDownPoint.Y == e.Location.Y))
的回报;

点currAutoS = innerpanel.AutoScrollPosition;
如果(mouseDownPoint.Y> e.Location.Y)
{
//手指向上滑动
如果(currAutoS.Y!= 0)
currAutoS。 Y = Math.Abs​​(currAutoS.Y) - 5;
}
,否则如果(mouseDownPoint.Y< e.Location.Y)
{
//手指滑下
currAutoS.Y = Math.Abs​​(currAutoS .Y)+ 5;
}
,否则
{
currAutoS.Y = Math.Abs​​(currAutoS.Y);
}

如果(mouseDownPoint.X> e.Location.X)
{
//手指向左滑动
如果(currAutoS.X! = 0)
currAutoS.X = Math.Abs​​(currAutoS.X) - 5;
}
,否则如果(mouseDownPoint.X< e.Location.X)
{
//手指滑动右侧
currAutoS.X = Math.Abs​​(currAutoS .X)+ 5;
}
,否则
{
currAutoS.X = Math.Abs​​(currAutoS.X);
}
innerpanel.AutoScrollPosition = currAutoS;
mouseDownPoint = e.Location; //重要

}


解决方案

而作为一个组件:

 公共部分类TouchableFlowLayoutPanel:FlowLayoutPanel的
{
私人布尔_doTouchScroll;
私人点_mouseStartPoint = Point.Empty;
私人点_panelStartPoint = Point.Empty;

///<总结>
///初始化℃的新的实例;参见CREF =TouchableFlowLayoutPanel/>类。
///< /总结>
公共TouchableFlowLayoutPanel()
{
的InitializeComponent();

Program.mouseFilter.MouseFilterDown + = mouseFilter_MouseFilterDown;
Program.mouseFilter.MouseFilterMove + = mouseFilter_MouseFilterMove;
Program.mouseFilter.MouseFilterUp + = mouseFilter_MouseFilterUp;
}

///<总结>
///初始化℃的新的实例;参见CREF =TouchableFlowLayoutPanel/>类。
///< /总结>
///&下; PARAM NAME =容器>将容器与所述; /参数>
公共TouchableFlowLayoutPanel(集装箱的IContainer)
{
container.Add(本);

的InitializeComponent();

Program.mouseFilter.MouseFilterDown + = mouseFilter_MouseFilterDown;
Program.mouseFilter.MouseFilterMove + = mouseFilter_MouseFilterMove;
Program.mouseFilter.MouseFilterUp + = mouseFilter_MouseFilterUp;
}

///<总结>
///来处理mouseFilter控制的MouseFilterDown事件。
///< /总结>
///< PARAM NAME =发件人>该事件的源< /参数>
///< PARAM NAME =E>
///在<见CREF =MouseFilterEventArgs/>实例包含事件数据。
///< /参数>
私人无效mouseFilter_MouseFilterDown(对象发件人,MouseFilterEventArgs E)
{
如果(_doTouchScroll&安培;!&安培; e.Button == MouseButtons.Left)
{
_mouseStartPoint =新的点(例如,EY);
_panelStartPoint =新的点(-AutoScrollPosition.X,
-AutoScrollPosition.Y);
}
}

///<总结>
///来处理mouseFilter控制的MouseFilterMove事件。
///< /总结>
///< PARAM NAME =发件人>该事件的源< /参数>
///< PARAM NAME =E>
///在<见CREF =MouseFilterEventArgs/>实例包含事件数据。
///< /参数>
私人无效mouseFilter_MouseFilterMove(对象发件人,MouseFilterEventArgs E)
{
如果(e.Button == MouseButtons.Left)
{
如果(!_mouseStartPoint.Equals( Point.Empty))
{
INT DX =(前 - _mouseStartPoint.X);
INT DY =(e.Y - _mouseStartPoint.Y);

如果(_doTouchScroll)
{
AutoScrollPosition =新的点(_panelStartPoint.X - DX,
_panelStartPoint.Y - DY);
}
,否则如果(Math.Abs​​(DX)大于10 || Math.Abs​​(DY)大于10)
{
_doTouchScroll = TRUE;
}
}
}
}

///<总结>
///来处理mouseFilter控制的MouseFilterUp事件。
///< /总结>
///< PARAM NAME =发件人>该事件的源< /参数>
///< PARAM NAME =E>
///在<见CREF =MouseFilterEventArgs/>实例包含事件数据。
///< /参数>
私人无效mouseFilter_MouseFilterUp(对象发件人,MouseFilterEventArgs E)
{
如果(e.Button == MouseButtons.Left)
{
如果(_doTouchScroll&安培;&安培; !AutoScrollPosition.Equals(_panelStartPoint)及和放大器;!
_panelStartPoint.Equals(Point.Empty))
{
//不会触发点击事件
e.Handled = TRUE;
}
_doTouchScroll = FALSE;
_mouseStartPoint = Point.Empty;
_panelStartPoint = Point.Empty;
}
}
}

内部类MouseFilter:IMessageFilter
{
私人const int的WM_LBUTTONDOWN = 0x0201;
私人const int的WM_LBUTTONUP = 0x0202;
私人const int的WM_MOUSEMOVE = 0x0200;

///<总结>
/// Filtert EINE Meldung,bevor SIE gesendet wird。
///< /总结>
///< PARAM NAME =M>模具祖sendende Meldung。 。Diese Meldung卡恩nicht修订于werden< /参数>
///<退货和GT;
///真实,嗯死Meldung祖filtern UND DAS Senden的祖verhindern。假的,嗯DAS Senden的德Meldung二的Zumnächsten过滤奥德Steuerelement祖ermöglichen。
///< /回报>
公共BOOL PreFilterMessage(参考消息M)
{
点mousePosition = Control.MousePosition;
变参=新MouseFilterEventArgs(MouseButtons.Left,0,mousePosition.X,mousePosition.Y,0);

开关(m.Msg)
{
情况下WM_MOUSEMOVE:
如果(MouseFilterMove!= NULL)
{
MouseFilterMove(控制。 FromHandle(m.HWnd),参数);
}
中断;

情况下WM_LBUTTONDOWN:
如果(!MouseFilterDown = NULL)
{
MouseFilterDown(Control.FromHandle(m.HWnd),参数);
}
中断;

情况下WM_LBUTTONUP:
如果(!MouseFilterUp = NULL)
{
MouseFilterUp(Control.FromHandle(m.HWnd),参数);
}
中断;
}

//总是允许消息继续下一个过滤器控制
返回args.Handled;
}

///<总结>
///当[鼠标筛选了]发生。
///< /总结>
公共事件MouseFilterEventHandler MouseFilterUp;

///<总结>
///当[鼠标下渗]发生。
///< /总结>
公共事件MouseFilterEventHandler MouseFilterDown;

///<总结>
///时发生[鼠标移动过滤器。
///< /总结>
公共事件MouseFilterMoveEventHandler MouseFilterMove;
}

内部委托无效MouseFilterEventHandler(对象发件人,MouseFilterEventArgs参数);

内部委托无效MouseFilterMoveEventHandler(对象发件人,MouseFilterEventArgs参数);

内部类MouseFilterEventArgs
{
///<总结>
///初始化中的<一个新的实例;见CREF =MouseFilterEventArgs/>类。
///< /总结>
///< PARAM NAME =mouseButton方式>鼠标按键与LT; /参数>
///< PARAM NAME =点击>在点击< /参数>
///&下; PARAM NAME =x的方式>的X&下; /参数>
///< PARAM NAME =Y方式>的y< /参数>
///< PARAM NAME =三角洲>在增量和LT; /参数>
公共MouseFilterEventArgs(MouseButtons mouseButton,点击诠释,诠释的x,INT Y,INT三角洲)
{
键= mouseButton;
点击次数=点击;
X = X;
Y = Y;
三角洲=三角洲;
处理的= FALSE;
}

///<总结>
///获取或设置按钮。
///< /总结>
///< VALUE>
///按钮。
///< /值>
公共MouseButtons按钮{搞定;组; }

///<总结>
///获取或设置一个值,指示是否该<见CREF =MouseFilterEventArgs/>被处理。
///< /总结>
///< VALUE>
///&所述c取代;真&下; / c取代;如果处理;否则,< c取代假LT; / c取代。
///< /值>
公共BOOL处理的{搞定;组; }

///<总结>
///获取或设置十
///< /总结>
///< VALUE>
///的十
///< /值>
公众诠释X {搞定;组; }

///<总结>
///获取或设置Y.
///< /总结>
///< VALUE>
///的Y.
///< /值>
公众诠释Ÿ{搞定;组; }

///<总结>
///获取或设置点击。
///< /总结>
///< VALUE>
///的点击。
///< /值>
公众诠释点击{搞定;组; }

///<总结>
///获取或设置三角洲。
///< /总结>
///< VALUE>
///三角洲。
///< /值>
公众诠释三角洲{搞定;组; }
}

静态类节目
{
公共静态MouseFilter mouseFilter =新MouseFilter();

///<总结>
///明镜Haupteinstiegspunkt献给死Anwendung。
///< /总结>
[STAThread]
静态无效的主要()
{
Application.AddMessageFilter(mouseFilter);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(假);
Application.Run(新的MainForm());
}
}


After scouring the articles online I have come up with this design for a winforms based touchscreen app that needs smartphone like scrolling. The app itself will run on a tablet laptop or touchscreen desktop.

  • I put everything I want to scroll on a panel.
  • Set autoscroll to true (which will show scrollbars)
  • Now put this whole panel inside a groupbox
  • Shrink the groupbox until the scrollbars are hidden (visually hidden, not visible = false)

Now the fun part I am stuck at. I think I have to handle the mousedown, mouseup & mousemove on the panel to set the autoscrollposition so that when someone touches the panel and drags, it does it's scroll magic. Please help fill in the few lines of code in below method stubs. The msdn doc on autoscrollposition is very confusing since it returns negative numbers but needs to be set to positive with abs and what not.

Point mouseDownPoint;
Point mouseUpPoint;
Point mouseDragPoint;
 private void myPanel_MouseDown(object sender, MouseEventArgs e)
 {
    this.mouseDownPoint = e.Location;
    Console.WriteLine("Mouse down at {0}", e.location);
 }

 private void myPanel_MouseUp(object sender, MouseEventArgs e)
 {
    this.mouseUpPoint = e.Location;
    this.mouseDownPoint = new Point(); //will set for IsEmpty check
    Console.WriteLine("Mouse Up at {0}", e.location);
 }

 private void myPanel_MouseMove(object sender, MouseEventArgs e)
 {
    Console.WriteLine("Mouse at {0}", e.location);
    if (mouseDownPoint.IsEmpty()) //finger is off the touchscreen
       return;
    myPanel.Autocrollposition = ??
 }

thank you

//UPDATE - Below I have with trial and error working & tested code. (not refactored). If someone has a more elegant solution please post.

    Point mouseDownPoint;
    private void innerpanel_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
            this.mouseDownPoint = e.Location;
    }

    private void innerpanel_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left)
            return;
        if ((mouseDownPoint.X == e.Location.X) && (mouseDownPoint.Y == e.Location.Y))
            return;

        Point currAutoS = innerpanel.AutoScrollPosition;
        if (mouseDownPoint.Y > e.Location.Y)
        {
            //finger slide UP
            if (currAutoS.Y != 0)
                currAutoS.Y = Math.Abs(currAutoS.Y) - 5;
        }
        else if (mouseDownPoint.Y < e.Location.Y)
        {
            //finger slide down
            currAutoS.Y = Math.Abs(currAutoS.Y) + 5;
        }
        else
        {
            currAutoS.Y = Math.Abs(currAutoS.Y);
        }

        if (mouseDownPoint.X > e.Location.X)
        {
            //finger slide left
            if (currAutoS.X != 0)
                currAutoS.X = Math.Abs(currAutoS.X) - 5;
        }
        else if (mouseDownPoint.X < e.Location.X)
        {
            //finger slide right
            currAutoS.X = Math.Abs(currAutoS.X) + 5;
        }
        else
        {
            currAutoS.X = Math.Abs(currAutoS.X);
        }
        innerpanel.AutoScrollPosition = currAutoS;
        mouseDownPoint = e.Location; //IMPORTANT

    }

解决方案

And as a Component:

public partial class TouchableFlowLayoutPanel : FlowLayoutPanel
{
    private bool _doTouchScroll;
    private Point _mouseStartPoint = Point.Empty;
    private Point _panelStartPoint = Point.Empty;

    /// <summary>
    ///     Initializes a new instance of the <see cref="TouchableFlowLayoutPanel" /> class.
    /// </summary>
    public TouchableFlowLayoutPanel()
    {
        InitializeComponent();

        Program.mouseFilter.MouseFilterDown += mouseFilter_MouseFilterDown;
        Program.mouseFilter.MouseFilterMove += mouseFilter_MouseFilterMove;
        Program.mouseFilter.MouseFilterUp += mouseFilter_MouseFilterUp;
    }

    /// <summary>
    ///     Initializes a new instance of the <see cref="TouchableFlowLayoutPanel" /> class.
    /// </summary>
    /// <param name="container">The container.</param>
    public TouchableFlowLayoutPanel(IContainer container)
    {
        container.Add(this);

        InitializeComponent();

        Program.mouseFilter.MouseFilterDown += mouseFilter_MouseFilterDown;
        Program.mouseFilter.MouseFilterMove += mouseFilter_MouseFilterMove;
        Program.mouseFilter.MouseFilterUp += mouseFilter_MouseFilterUp;
    }

    /// <summary>
    ///     Handles the MouseFilterDown event of the mouseFilter control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">
    ///     The <see cref="MouseFilterEventArgs" /> instance containing the event data.
    /// </param>
    private void mouseFilter_MouseFilterDown(object sender, MouseFilterEventArgs e)
    {
        if (!_doTouchScroll && e.Button == MouseButtons.Left)
        {
            _mouseStartPoint = new Point(e.X, e.Y);
            _panelStartPoint = new Point(-AutoScrollPosition.X,
                                                 -AutoScrollPosition.Y);
        }
    }

    /// <summary>
    ///     Handles the MouseFilterMove event of the mouseFilter control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">
    ///     The <see cref="MouseFilterEventArgs" /> instance containing the event data.
    /// </param>
    private void mouseFilter_MouseFilterMove(object sender, MouseFilterEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            if (!_mouseStartPoint.Equals(Point.Empty))
            {
                int dx = (e.X - _mouseStartPoint.X);
                int dy = (e.Y - _mouseStartPoint.Y);

                if (_doTouchScroll)
                {
                    AutoScrollPosition = new Point(_panelStartPoint.X - dx,
                                                   _panelStartPoint.Y - dy);
                }
                else if (Math.Abs(dx) > 10 || Math.Abs(dy) > 10)
                {
                    _doTouchScroll = true;
                }
            }
        }
    }

    /// <summary>
    ///     Handles the MouseFilterUp event of the mouseFilter control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">
    ///     The <see cref="MouseFilterEventArgs" /> instance containing the event data.
    /// </param>
    private void mouseFilter_MouseFilterUp(object sender, MouseFilterEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            if (_doTouchScroll && !AutoScrollPosition.Equals(_panelStartPoint) &&
                !_panelStartPoint.Equals(Point.Empty))
            {
                // don't fire Click-Event
                e.Handled = true;
            }
            _doTouchScroll = false;
            _mouseStartPoint = Point.Empty;
            _panelStartPoint = Point.Empty;
        }
    }
}

internal class MouseFilter : IMessageFilter
{
    private const int WM_LBUTTONDOWN = 0x0201;
    private const int WM_LBUTTONUP = 0x0202;
    private const int WM_MOUSEMOVE = 0x0200;

    /// <summary>
    ///     Filtert eine Meldung, bevor sie gesendet wird.
    /// </summary>
    /// <param name="m">Die zu sendende Meldung. Diese Meldung kann nicht geändert werden.</param>
    /// <returns>
    ///     true, um die Meldung zu filtern und das Senden zu verhindern. false, um das Senden der Meldung bis zum nächsten Filter oder Steuerelement zu ermöglichen.
    /// </returns>
    public bool PreFilterMessage(ref Message m)
    {
        Point mousePosition = Control.MousePosition;
        var args = new MouseFilterEventArgs(MouseButtons.Left, 0, mousePosition.X, mousePosition.Y, 0);

        switch (m.Msg)
        {
            case WM_MOUSEMOVE:
                if (MouseFilterMove != null)
                {
                    MouseFilterMove(Control.FromHandle(m.HWnd), args);
                }
                break;

            case WM_LBUTTONDOWN:
                if (MouseFilterDown != null)
                {
                    MouseFilterDown(Control.FromHandle(m.HWnd), args);
                }
                break;

            case WM_LBUTTONUP:
                if (MouseFilterUp != null)
                {
                    MouseFilterUp(Control.FromHandle(m.HWnd), args);
                }
                break;
        }

        // Always allow message to continue to the next filter control
        return args.Handled;
    }

    /// <summary>
    ///     Occurs when [mouse filter up].
    /// </summary>
    public event MouseFilterEventHandler MouseFilterUp;

    /// <summary>
    ///     Occurs when [mouse filter down].
    /// </summary>
    public event MouseFilterEventHandler MouseFilterDown;

    /// <summary>
    ///     Occurs when [mouse filter move].
    /// </summary>
    public event MouseFilterMoveEventHandler MouseFilterMove;
}

internal delegate void MouseFilterEventHandler(object sender, MouseFilterEventArgs args);

internal delegate void MouseFilterMoveEventHandler(object sender, MouseFilterEventArgs args);

internal class MouseFilterEventArgs
{
    /// <summary>
    ///     Initializes a new instance of the <see cref="MouseFilterEventArgs" /> class.
    /// </summary>
    /// <param name="mouseButton">The mouse button.</param>
    /// <param name="clicks">The clicks.</param>
    /// <param name="x">The x.</param>
    /// <param name="y">The y.</param>
    /// <param name="delta">The delta.</param>
    public MouseFilterEventArgs(MouseButtons mouseButton, int clicks, int x, int y, int delta)
    {
        Button = mouseButton;
        Clicks = clicks;
        X = x;
        Y = y;
        Delta = delta;
        Handled = false;
    }

    /// <summary>
    ///     Gets or sets the button.
    /// </summary>
    /// <value>
    ///     The button.
    /// </value>
    public MouseButtons Button { get; set; }

    /// <summary>
    ///     Gets or sets a value indicating whether this <see cref="MouseFilterEventArgs" /> is handled.
    /// </summary>
    /// <value>
    ///     <c>true</c> if handled; otherwise, <c>false</c>.
    /// </value>
    public bool Handled { get; set; }

    /// <summary>
    ///     Gets or sets the X.
    /// </summary>
    /// <value>
    ///     The X.
    /// </value>
    public int X { get; set; }

    /// <summary>
    ///     Gets or sets the Y.
    /// </summary>
    /// <value>
    ///     The Y.
    /// </value>
    public int Y { get; set; }

    /// <summary>
    ///     Gets or sets the clicks.
    /// </summary>
    /// <value>
    ///     The clicks.
    /// </value>
    public int Clicks { get; set; }

    /// <summary>
    ///     Gets or sets the delta.
    /// </summary>
    /// <value>
    ///     The delta.
    /// </value>
    public int Delta { get; set; }
}

static class Program
{
    public static MouseFilter mouseFilter = new MouseFilter();

    /// <summary>
    /// Der Haupteinstiegspunkt für die Anwendung.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.AddMessageFilter(mouseFilter);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }
}

这篇关于如何让智能手机像滚动的一个WinForms触摸屏应用(滚动面板)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆