Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Qt 鼠标交互的设计模式_Qt_Design Patterns - Fatal编程技术网

Qt 鼠标交互的设计模式

Qt 鼠标交互的设计模式,qt,design-patterns,Qt,Design Patterns,我需要一些关于什么是通用鼠标的“理想”设计模式的意见 互动 这里是简化的问题。我有一个小的3d程序(QT和openGL)和 我使用鼠标进行交互。每一次互动通常不仅仅是一次 单个函数调用,主要由多达3个函数调用(initiate、perform、finalize)执行。 例如,摄影机旋转:这里的初始函数调用将传递当前的第一个鼠标位置, 而执行函数调用将更新摄像机等 但是,仅对几个交互进行硬编码(在MousePresseEvent、MouseReleaseEvent、MouseMouseVeveEv

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

这里是简化的问题。我有一个小的3d程序(QT和openGL)和 我使用鼠标进行交互。每一次互动通常不仅仅是一次 单个函数调用,主要由多达3个函数调用(initiate、perform、finalize)执行。 例如,摄影机旋转:这里的初始函数调用将传递当前的第一个鼠标位置, 而执行函数调用将更新摄像机等

但是,仅对几个交互进行硬编码(在MousePresseEvent、MouseReleaseEvent、MouseMouseVeveEvent或MouseWheelEvent等内部) 这没什么大不了的,但是如果我考虑一个更高级的程序(例如20个或更多的交互),那么就需要一个合适的设计

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

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


谢谢

Qt让这一切变得非常简单

与您以前编写的所有
切换鼠标模式:
功能不同,只需让每个鼠标事件处理程序函数发出一个信号,即mouseDown/mouseUp/mousePosition,并使用信号/插槽将它们路由到相应的模型函数


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

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

在我的Qt程序中,我有带有mousePressEvent、mouseMoveEvent和mouseReleaseEvent的QGraphicsCenes和QGraphicsSitems,它们看起来如下:

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,因为它基本上就是构造函数

这当然是一个相当具体的例子,可能并不完全是你想要的,但它让你了解了如何使用多态性来清理鼠标操作。

我发现苹果的设计非常好,而且可以扩展

其想法是将手势(或交互)的识别与将被触发的动作分离

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

例如,你的基本类是:(对不起我的可怜的半C++伪代码…最近我不怎么使用它)

如果你想检测鼠标的滑动

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);
}
只要确保在事件发生时调用上述方法,并且它们应该在需要时调用目标

这就是目标在我看来的样子:

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的实现非常好,允许为同一个识别器注册多个目标/方法,并将多个识别器注册到同一视图。 UI手势识别器有一个委托对象,用于获取有关其他手势识别器的信息,例如,如果可以同时检测到两个手势,或者一个手势必须在检测到另一个手势后立即失败,等等

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

我认为值得一看


希望有帮助:)

感谢Anthony的详细回答。我将尝试实现工厂方法,并结合信号/插槽机制。否则,我看不出如何将openGL拾取(它只给我一些ID)与实际对象连接起来。Martin,谢谢你的回复。结合工厂模式,信号/插槽可能是一个简洁的解决方案。您好nacho4d,非常感谢您的详细回答。目前,针对我的具体问题,手势识别器的设计似乎过于笼统。不过,我会把它记在心里,供以后使用。谢谢
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?
    }
}