首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >鼠标交互的设计模式

鼠标交互的设计模式
EN

Stack Overflow用户
提问于 2012-04-13 00:56:39
回答 3查看 920关注 0票数 3

我需要一些关于什么是一般鼠标交互的“理想”设计模式的意见。

这里是简化的问题。我有一个小的3d程序(QT和openGL),我使用鼠标进行交互。每个交互通常不只是一个函数调用,它主要由最多3个函数调用(initiate,perform,finalize)来执行。例如,相机旋转:这里的初始函数调用将提供当前的第一个鼠标位置,而执行的函数调用将更新相机等。

然而,对于只有几个交互,硬编码这些(在MousePressEvent,MouseReleaseEvent MouseMoveEvent或MouseWheelEvent等中)并不是什么大问题,但如果我考虑一个更高级的程序(例如20个或更多交互),那么就需要一个适当的设计。

因此,您如何在QT中设计这样的交互。

我希望我把我的问题说得够清楚了,否则就别抱怨了:-)

谢谢

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-04-13 02:02:32

我建议使用多态性和工厂方法模式。下面是一个例子:

在我的Qt程序中,我有带有mousePressEvent、mouseMoveEvent和mouseReleaseEvent的QGraphicsScenes和QGraphicsItems,它们看起来像这样:

代码语言:javascript
复制
void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
  // call factory method, which returns a subclass depending on where click occurred
  dragHandler = DragHandler::createDragHandler(event /* and other relevant stuff */);
}

void CustomItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
  dragHandler->onMouseMove(event);
}

void CustomItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
  dragHandler->onMouseRelease(event);
  delete dragHandler;
}

本例中的想法是,根据我在CustomItem上单击的位置,按下鼠标、移动鼠标和释放鼠标将具有不同的功能。例如,如果我单击项目的边缘,拖动将调整它的大小,但如果我在项目的中间单击,拖动将移动它。DragHandler::onMouseMove和DragHandler::onMouseRelease是由子类重新实现的虚拟函数,以提供我想要的特定功能,具体取决于鼠标按下发生的位置。没有必要使用DragHandler::onMousePress,因为它基本上就是构造函数。

当然,这是一个相当具体的示例,可能不是您想要的,但它让您了解了如何使用多态性来清理鼠标处理。

票数 4
EN

Stack Overflow用户

发布于 2012-04-13 01:25:43

Qt让这一切变得非常简单。

不需要编写所有的switch mouse_mode:代码,只需让每个鼠标事件处理函数发出一个信号即可。mouseDown/mouseUp/mousePosition,并使用信号/插槽将这些信号路由到适当的模型函数。

然后,您可以通过连接/断开Mouse...Event()中发送的信号的不同插槽来适应鼠标的不同用途(选择、旋转、编辑等)

票数 1
EN

Stack Overflow用户

发布于 2012-04-13 02:25:06

我觉得苹果的UIGestureRecognizer设计相当不错,而且很有可扩展性。

这个想法是将手势(或交互)和将被触发的动作的识别解耦。

您需要实现一个基本的或抽象的GestureRecognizer类,该类能够基于事件MousePressEvent、MouseReleaseEvent MouseMoveEvent或MouseWheelEvent等识别特定的交互或手势。GestureRecongnizers有一个定期报告更改的目标。

例如,您最基本的类应该是:(对不起,我可怜的半c++伪代码...最近我不经常使用它)

代码语言:javascript
复制
class Recognizer {
int state; // ex: 0:possible, 1:began, 2:changed, 3:ended/recognized 4:cancelled
protected:
void setTarget(void &theTarget); // or even better a touple, target/method. In this case target is assumed to have a method gestureHandle(Recognizer *r);
virtual void mouserPress() = 0;
virtual void mouserRelease() = 0;
virtual void mouserMove() = 0;
virtual void mouserWheel() = 0;
...
}

如果你想用鼠标检测滑动

代码语言:javascript
复制
class SwipeRecognizer : Recognizer {
int direction; // ex: 0:left2right 1:bottom2top 2:...
private:
void mouserPress() {
    state = 0; // possible. You don't know yet is the mouse is going to swipe, simple click, long press, etc.
    // save some values so you can calculate the direction of the swipe later 
    target.gestureHandle(this);
};
void mouserMove() {
    if (state == 0) {
        state = 1; // it was possible now you know the swipe began!
        direction = ... // calculate the swipe direction here
    } else if (state == 1 || state == 2) {// state is began or changed
        state = 2; // changed ... which means is still mouse dragging
        // probably you want to make more checks here like you are still swiping in the same direction you started, maybe velocity thresholds, if any of your conditions are not met you should cancel the gesture recognizer by setting its state to 4
    }
    target.gestureHandler(this);
};
void mouserRelease() {
    if (state == 2) { // is swipping
        state = 3; // swipe ended
    } else {
        state = 4; // it was not swiping so simple cancel the tracking
    }
    target.gestureHandler(this);
};
void mouserWheel() {
    // if this method is called then this is definitely not a swipe right?
    state = 4; // cancelled
    target.gestureHandler(this);
}

只需确保上述方法在事件发生时被调用,并且它们应该在需要时调用目标。

在我看来,目标是这样的:

代码语言:javascript
复制
class Target {
...
void gestureHandler(Recognizer *r) {
    if (r->state == 2) {
        // Is swipping: move the opengl camera using some parameter your recognizer class brings
    } else if (r->state == 3) {
        // ended: stop moving the opengl camera
    } else if (r->state == 4) {
        // Cancelled, maybe restore camera to original position?
    }
}

UIGestureRecognizer的实现相当不错,它允许为同一识别器注册多个目标/method,并将多个识别器注册到同一视图。UIGestureRecognizers有一个委托对象,用于获取有关其他手势识别器的信息,例如,如果可以同时检测到两个手势,或者其中一个必须在检测到另一个手势时立即失败,等等。

一些手势识别器需要比其他手势识别器更多的覆盖,但最大的好处是它们的输出是相同的:通知当前状态(和其他信息)的处理程序方法。

我觉得值得一看。

希望它能有所帮助:)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10128200

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档