设置QWidget可移动可改变大小可取消菜单栏的公共程序

一、NcFramelessHelper.h


//Version 3.0.0

#ifndef NC_FRAMELESS_HELPER_H
#define NC_FRAMELESS_HELPER_H

#include <QObject>

class NcFramelessHelperImpl;

class NcFramelessHelper : public QObject
{

public:
  explicit NcFramelessHelper( QObject* parent = 0 );
  ~NcFramelessHelper();

  void activateOn( QWidget* topLevelWidget );
  void removeFrom( QWidget* topLevelWidget );

  void setWidgetMovable( bool movable );
  bool isWidgetMovable();

  void setWidgetResizable( bool resizable );
  bool isWidgetResizable();

  void useRubberBandOnMove( bool use );
  bool isUsingRubberBandOnMove();

  void useRubberBandOnResize( bool use );
  bool isUsingRubberBandOnResisze();

  void setIsGlobal(bool global);
  bool isGlobal();

  //Make sure to leave the same content margins
  //around the widget as the newBorderWidth
  //this can be done by
  //yourWidget->layout()->setMargin( newBorderWidth );
  //otherwise your widget will not expose the
  //area where this class works
  void setBorderWidth( int newBorderWidth );
  int borderWidth();

protected:
  virtual bool eventFilter( QObject* obj, QEvent* event );

private:
  NcFramelessHelperImpl* d;
};

#endif // NC_FRAMELESS_HELPER_H

二、NcFramelessHelper.cpp


#include <QRubberBand>
#include <QMouseEvent>
#include <QMutex>
#include <QDebug>
#include "NcFramelessHelper.h"

class NcCursorPosCalculator
{

public:
  NcCursorPosCalculator();
  void reset();
  void recalculate( const QPoint& globalMousePos, const QRect& frameRect );

public:
  bool onEdges;
  bool onLeftEdge;
  bool onRightEdge;
  bool onTopEdge;
  bool onBottomEdge;
  bool onTopLeftEdge;
  bool onBottomLeftEdge;
  bool onTopRightEdge;
  bool onBottomRightEdge;

  static int mBorderWidth;
};
//TODO: Should not be static.
int NcCursorPosCalculator::mBorderWidth = 5;

class NcWidgetData
{
public:
  NcWidgetData( NcFramelessHelperImpl* _d, QWidget* topLevelWidget );
  ~NcWidgetData();

  //void setWidget( QWidget* topLevelWidget );
  QWidget* widget();
  void handleWidgetEvent( QEvent* event );
  void updateRubberBandStatus();
  void setGlobal(bool global);
private:
  void updateCursorShape( const QPoint& globalMousePos );
  void resizeWidget( const QPoint& globalMousePos );
  void moveWidget( const QPoint& globalMousePos );

  void handleMousePressEvent( QMouseEvent* event );
  void handleMouseReleaseEvent( QMouseEvent* event );
  void handleMouseMoveEvent( QMouseEvent* event );
  void handleLeaveEvent( QEvent* event );
  void handleHoverMoveEvent( QHoverEvent* event );

private:
  NcFramelessHelperImpl* d;
  QRubberBand* mRubberBand;
  bool mLeftButtonPressed;
  QWidget* mWidget;
  QPoint mDragPos;
  NcCursorPosCalculator mPressedMousePos;
  NcCursorPosCalculator mMoveMousePos;
  bool mCursorShapeChanged;
  Qt::WindowFlags mWindowFlags;
  bool mGlobal;
};


class NcFramelessHelperImpl
{
public:
  QHash< QWidget*, NcWidgetData* > mHashWidgetData;
  bool mWidgetMovable;
  bool mWidgetResizable;
  bool mUseRubberBandOnResize;
  bool mUseRubberBandOnMove;
  bool mGlobal;
};

NcCursorPosCalculator::NcCursorPosCalculator()
{
  reset();
}

void NcCursorPosCalculator::reset()
{
  onEdges = false;
  onLeftEdge = false;
  onRightEdge = false;
  onTopEdge = false;
  onBottomEdge = false;
  onTopLeftEdge = false;
  onBottomLeftEdge = false;
  onTopRightEdge = false;
  onBottomRightEdge = false;
}

void NcCursorPosCalculator::recalculate( const QPoint& globalMousePos, const QRect& frameRect )
{
  int globalMouseX = globalMousePos.x();
  int globalMouseY = globalMousePos.y();

  int frameX = frameRect.x();
  int frameY = frameRect.y();

  int frameWidth = frameRect.width();
  int frameHeight = frameRect.height();


  onLeftEdge = globalMouseX >= frameX &&
      globalMouseX <= frameX + mBorderWidth;


  onRightEdge = globalMouseX >= frameX + frameWidth - mBorderWidth &&
      globalMouseX <= frameX + frameWidth;

  onTopEdge = globalMouseY >= frameY &&
      globalMouseY <= frameY + mBorderWidth;


  onBottomEdge = globalMouseY >= frameY + frameHeight - mBorderWidth &&
      globalMouseY <= frameY + frameHeight;

  onTopLeftEdge = onTopEdge && onLeftEdge;
  onBottomLeftEdge = onBottomEdge && onLeftEdge;
  onTopRightEdge = onTopEdge && onRightEdge;
  onBottomRightEdge = onBottomEdge && onRightEdge;

  //only these checks would be enough
  onEdges = onLeftEdge || onRightEdge ||
      onTopEdge || onBottomEdge;

}


NcWidgetData::NcWidgetData( NcFramelessHelperImpl* _d, QWidget* topLevelWidget )
{
  d = _d;
  mWidget = topLevelWidget;
  mLeftButtonPressed = false;
  mRubberBand = 0;
  mCursorShapeChanged = false;
  mGlobal = true;
  mWindowFlags = mWidget->windowFlags();

  //---from Qt docs of setWindowFlags()----
  //Note: This function calls setParent() when
  //changing the flags for a window, causing the
  //widget to be hidden. You must call show()
  //to make the widget visible again..

  bool visible = mWidget->isVisible();

  mWidget->setMouseTracking( true );
  mWidget->setWindowFlags( /*Qt::CustomizeWindowHint|*/mWidget->windowFlags() | Qt::FramelessWindowHint|Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint);
  //Bug fix, mouse move events does not propagate from child widgets.
  //so need the hover events.
  mWidget->setAttribute( Qt::WA_Hover );

  updateRubberBandStatus();

  mWidget->setVisible( visible );
}

NcWidgetData::~NcWidgetData()
{
  //---from Qt docs of setWindowFlags()----
  //Note: This function calls setParent() when
  //changing the flags for a window, causing the
  //widget to be hidden. You must call show()
  //to make the widget visible again..

  bool visible = mWidget->isVisible();

  mWidget->setMouseTracking( false );
  mWidget->setWindowFlags( mWindowFlags );//^  Qt::CustomizeWindowHint ^ Qt::FramelessWindowHint );
  mWidget->setAttribute( Qt::WA_Hover, false );

  mWidget->setVisible( visible );

  delete mRubberBand;
}

void NcWidgetData::updateRubberBandStatus()
{
  if ( d->mUseRubberBandOnMove || d->mUseRubberBandOnResize )
  {
    if ( !mRubberBand )
      mRubberBand = new QRubberBand( QRubberBand::Rectangle );
  }
  else
  {
    delete mRubberBand;
    mRubberBand = 0;
  }
}

void NcWidgetData::setGlobal(bool global)
{
    mGlobal = global;
}

QWidget* NcWidgetData::widget()
{
  return mWidget;
}

void NcWidgetData::handleWidgetEvent( QEvent* event )
{
  switch ( event->type() )
  {
  default: //qDebug() << "Event = " << event;
    break;
  case QEvent::MouseButtonPress:
    handleMousePressEvent( static_cast<QMouseEvent*>( event ) );
    break;

  case QEvent::MouseButtonRelease:
    handleMouseReleaseEvent( static_cast<QMouseEvent*>( event ) );
    break;

  case QEvent::MouseMove:
    handleMouseMoveEvent( static_cast<QMouseEvent*>( event ) );
    break;

  case QEvent::Leave:
    handleLeaveEvent( event );
    break;

    //Bug fix, hover event is necessary coz child widget does not
    //propagate mousemove events. so the cursor remains in edge shape
    //even in middle of widget.
  case QEvent::HoverMove:
    handleHoverMoveEvent( static_cast<QHoverEvent*>( event ) );
    break;
    //case QEvent::Enter:
    //qDebug() << "Enter event";//d->handleEnterEvent( event );
    //break;
  }
}

void NcWidgetData::updateCursorShape( const QPoint& globalMousePos )
{
  if ( mWidget->isFullScreen() || mWidget->isMaximized() )
  {
    if ( mCursorShapeChanged )
      mWidget->unsetCursor();

    return;
  }

  mMoveMousePos.recalculate( globalMousePos, mWidget->frameGeometry() );

  if( mMoveMousePos.onTopLeftEdge || mMoveMousePos.onBottomRightEdge )
  {
    mWidget->setCursor( Qt::SizeFDiagCursor );
    mCursorShapeChanged = true;
  }
  else if( mMoveMousePos.onTopRightEdge || mMoveMousePos.onBottomLeftEdge )
  {
    mWidget->setCursor( Qt::SizeBDiagCursor );
    mCursorShapeChanged = true;
  }
  else if( mMoveMousePos.onLeftEdge || mMoveMousePos.onRightEdge )
  {
    mWidget->setCursor( Qt::SizeHorCursor );
    mCursorShapeChanged = true;
  }
  else if( mMoveMousePos.onTopEdge || mMoveMousePos.onBottomEdge )
  {
    mWidget->setCursor( Qt::SizeVerCursor );
    mCursorShapeChanged = true;
  }
  else
  {
    if ( mCursorShapeChanged )
    {
      mWidget->unsetCursor();
      mCursorShapeChanged = false;
    }
  }
}

void NcWidgetData::resizeWidget( const QPoint& globalMousePos )
{
  QRect origRect;

  if ( d->mUseRubberBandOnResize )
    origRect = mRubberBand->frameGeometry();
  else
    origRect = mWidget->frameGeometry();


  int left = origRect.left();
  int top = origRect.top();
  int right = origRect.right();
  int bottom = origRect.bottom();
  origRect.getCoords( &left, &top, &right, &bottom );

  int minWidth = mWidget->minimumWidth();
  int minHeight = mWidget->minimumHeight();

  if ( mPressedMousePos.onTopLeftEdge )
  {
    left = globalMousePos.x();
    top = globalMousePos.y();
  }
  else if ( mPressedMousePos.onBottomLeftEdge )
  {
    left = globalMousePos.x();
    bottom = globalMousePos.y();
  }
  else if ( mPressedMousePos.onTopRightEdge )
  {
    right = globalMousePos.x();
    top = globalMousePos.y();
  }
  else if ( mPressedMousePos.onBottomRightEdge )
  {
    right = globalMousePos.x();
    bottom = globalMousePos.y();
  }
  else if ( mPressedMousePos.onLeftEdge )
  {
    left = globalMousePos.x();
  }
  else if ( mPressedMousePos.onRightEdge )
  {
    right = globalMousePos.x();
  }
  else if ( mPressedMousePos.onTopEdge )
  {
    top = globalMousePos.y();
  }
  else if ( mPressedMousePos.onBottomEdge )
  {
    bottom = globalMousePos.y();
  }

  QRect newRect( QPoint(left, top), QPoint(right, bottom) );

  if ( newRect.isValid() )
  {
    if ( minWidth > newRect.width() )
    {
      //determine what has caused the width change.
      if( left != origRect.left() )
        newRect.setLeft( origRect.left() );
      else
        newRect.setRight( origRect.right() );
    }
    if ( minHeight > newRect.height() )
    {
      //determine what has caused the height change.
      if ( top != origRect.top() )
        newRect.setTop( origRect.top() );
      else
        newRect.setBottom( origRect.bottom() );
    }

    if ( d->mUseRubberBandOnResize )
    {
      mRubberBand->setGeometry( newRect );
    }
    else
    {
      mWidget->setGeometry( newRect );
    }
  }
  else
  {
    //qDebug() << "Calculated Rect is not valid" << newRect;
  }

}

void NcWidgetData::moveWidget( const QPoint& globalMousePos )
{
  if ( d->mUseRubberBandOnMove )
  {
    mRubberBand->move( globalMousePos - mDragPos );
  }
  else
  {
    mWidget->move( globalMousePos - mDragPos );
  }
}

void NcWidgetData::handleMousePressEvent( QMouseEvent* event )
{
  if ( event->button() == Qt::LeftButton )
  {
    mLeftButtonPressed = true;

    QRect frameRect = mWidget->frameGeometry();
    if(mGlobal)
    {
        mPressedMousePos.recalculate( event->globalPos(), frameRect );
        mDragPos = event->globalPos() - frameRect.topLeft();
    }else{
        mPressedMousePos.recalculate( mWidget->mapToParent(event->pos()), frameRect );
        mDragPos = event->globalPos() - frameRect.topLeft();
    }

    if ( mPressedMousePos.onEdges  )
    {
      if ( d->mUseRubberBandOnResize )
      {
        mRubberBand->setGeometry( frameRect );
        mRubberBand->show();
      }
    }
    else if ( d->mUseRubberBandOnMove )
    {
      mRubberBand->setGeometry( frameRect );
      mRubberBand->show();
    }

  }
}

void NcWidgetData::handleMouseReleaseEvent( QMouseEvent* event )
{
  if ( event->button() == Qt::LeftButton )
  {
    mLeftButtonPressed = false;
    mPressedMousePos.reset();
    if ( mRubberBand && mRubberBand->isVisible() )
    {
      mRubberBand->hide();
      mWidget->setGeometry( mRubberBand->geometry() );
    }
  }
}

void NcWidgetData::handleMouseMoveEvent( QMouseEvent* event )
{
  if ( mLeftButtonPressed )
  {
    if ( d->mWidgetResizable && mPressedMousePos.onEdges )
    {
        if(mGlobal)
            resizeWidget( event->globalPos() );
        else
            resizeWidget( mWidget->mapToParent(event->pos()) );
    }
    else if ( d->mWidgetMovable )
    {
        if(mGlobal)
            moveWidget( event->globalPos() );
        else
            moveWidget( event->globalPos() );
    }
  }
  else if ( d->mWidgetResizable )
  {
      if(mGlobal)
          updateCursorShape( event->globalPos() );
      else
          updateCursorShape( mWidget->mapToParent(event->pos()) );
  }

}

void NcWidgetData::handleLeaveEvent( QEvent* /*event*/ )
{
  if ( !mLeftButtonPressed )
    mWidget->unsetCursor();
}

void NcWidgetData::handleHoverMoveEvent( QHoverEvent* event )
{
  if ( d->mWidgetResizable )
  {
      if(mGlobal)
          updateCursorShape( mWidget->mapToGlobal( event->pos() ) );
      else
          updateCursorShape( mWidget->mapToParent(event->pos()));
  }
}

NcFramelessHelper::NcFramelessHelper( QObject* parent )
  : QObject( parent ),
    d( new NcFramelessHelperImpl )
{
  d->mWidgetMovable = true;
  d->mWidgetResizable = true;
  d->mUseRubberBandOnResize = false;
  d->mUseRubberBandOnMove = false;
  d->mGlobal = true;
}

NcFramelessHelper::~NcFramelessHelper()
{
  QList<QWidget*> keys = d->mHashWidgetData.keys();
  int size = keys.size();
  for ( int i = 0; i < size; ++i )
  {
    delete d->mHashWidgetData.take( keys[i] );
  }

  delete d;
}

bool NcFramelessHelper::eventFilter( QObject *obj, QEvent *event )
{
  QEvent::Type type = event->type();

  if ( type == QEvent::MouseMove ||
       type == QEvent::HoverMove ||
       type == QEvent::MouseButtonPress ||
       type == QEvent::MouseButtonRelease ||
       type == QEvent::Leave
     )
 {
   NcWidgetData* data = d->mHashWidgetData.value( static_cast<QWidget*>(obj) );
   if ( data )
   {
     data->handleWidgetEvent( event );
   }

 }

  return false;
}

void NcFramelessHelper::activateOn( QWidget* topLevelWidget )
{
  if ( d->mHashWidgetData.contains( topLevelWidget ) )
    return;

  NcWidgetData* data = new NcWidgetData( d, topLevelWidget );
  data->setGlobal(d->mGlobal);
  d->mHashWidgetData.insert( topLevelWidget, data );

  topLevelWidget->installEventFilter( this );

}

void NcFramelessHelper::removeFrom( QWidget* topLevelWidget )
{
  NcWidgetData* data = d->mHashWidgetData.take( topLevelWidget );
  if ( data )
  {
    topLevelWidget->removeEventFilter( this );
    delete data;
  }
}

void NcFramelessHelper::setWidgetMovable( bool movable )
{
  d->mWidgetMovable = movable;
}

bool NcFramelessHelper::isWidgetMovable()
{
  return d->mWidgetMovable;
}

void NcFramelessHelper::setWidgetResizable( bool resizable )
{
  d->mWidgetResizable = resizable;
}

bool NcFramelessHelper::isWidgetResizable()
{
  return d->mWidgetResizable;
}

void NcFramelessHelper::useRubberBandOnMove( bool use )
{
  d->mUseRubberBandOnMove = use;
  QList<NcWidgetData*> list = d->mHashWidgetData.values();
  int size = list.size();
  for ( int i = 0; i < size; ++i )
    list[i]->updateRubberBandStatus();
}

bool NcFramelessHelper::isUsingRubberBandOnMove()
{
  return d->mUseRubberBandOnMove;
}

void NcFramelessHelper::useRubberBandOnResize( bool use )
{
  d->mUseRubberBandOnResize = use;
  QList<NcWidgetData*> list = d->mHashWidgetData.values();
  int size = list.size();
  for ( int i = 0; i < size; ++i )
    list[i]->updateRubberBandStatus();
}

bool NcFramelessHelper::isUsingRubberBandOnResisze()
{
    return d->mUseRubberBandOnResize;
}

void NcFramelessHelper::setIsGlobal(bool global)
{
    d->mGlobal = global;
}

bool NcFramelessHelper::isGlobal()
{
    return d->mGlobal;
}

void NcFramelessHelper::setBorderWidth( int newBorderWidth )
{
  //TODO: Make it non-static.
  if ( newBorderWidth >= 0 )
    NcCursorPosCalculator::mBorderWidth = newBorderWidth;
}

int NcFramelessHelper::borderWidth()
{
  return NcCursorPosCalculator::mBorderWidth;
}

三、调用方式

	NcFramelessHelper *Frameless = new NcFramelessHelper(this);
	//设置是否能移动
	Frameless->setWidgetMovable(true);
	Frameless->activateOn(this);
	//设置是否能改变大小
	Frameless->setWidgetResizable(false);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值