部件之间图标拖拽

又到周末了,尝试实现一个图标拖拽的小程序;主要实现的功能有:

1.两个部件的图标拖动转移

2.可以切换图标查看模式,有大图标和小图标模式两种

3.可以删除图标,添加也应该不难,所以就没实现。

4.可以框选多个图标

5.改变部件大小可以自动重新布局图标

这里初始化左边有十几个图标,右边的部件是空的。

主窗口

class MainWindow:public QMainWindow
{
	Q_OBJECT
public:
	MainWindow(QWidget *parent = NULL);
	~MainWindow();

private:
	Splitter    *m_pSplitter;
	MainWidget   *m_pLeftWidget;
	MainWidget   *m_pRightWidget;
	QScrollArea  *m_pSplitterArea;
};

MainWindow::MainWindow( QWidget *parent /*= NULL*/ ):QMainWindow(parent)
{
	this->setWindowTitle("IconDemo");
	m_pSplitter = new Splitter(this);
	m_pLeftWidget = new MainWidget(this);
	m_pLeftWidget->init();
	m_pRightWidget = new MainWidget(this);

	QSize size = m_pRightWidget->size();
	m_pSplitterArea = new QScrollArea(this);
	m_pSplitterArea->setWidget(m_pSplitter);
	m_pSplitter->addWidget(m_pLeftWidget);
	m_pSplitter->addWidget(m_pRightWidget);
	m_pSplitter->setMinimumSize(QSize(700,700));
	m_pSplitterArea->setMinimumSize(QSize(700,600));

	m_pSplitter->setCollapsible(0,false);
	m_pSplitter->setCollapsible(1,false);

	this->setStyleSheet(" QFrame{background-image: url(:/DragIcon/Resources/51.jpg) }");

	this->setFixedSize(QSize(700,550));
	connect(m_pLeftWidget,SIGNAL(heightChangeSignal(int)),m_pSplitter,SLOT(heightChangeSlot(int  )));
	connect(m_pRightWidget,SIGNAL(heightChangeSignal(int)),m_pSplitter,SLOT(heightChangeSlot(int )));

}

MainWindow::~MainWindow()
{

}

分割器

自定义分割器主要是为了在调节的时候可以改变其高度
class Splitter:public QSplitter
{
	Q_OBJECT
public:
	Splitter(QWidget *parent = NULL);
	~Splitter();
protected slots:
	void heightChangeSlot(int height);
private:
};

Splitter::Splitter( QWidget *parent /*= NULL*/ ):QSplitter(parent)
{

}

Splitter::~Splitter()
{

}

void Splitter::heightChangeSlot( int height )
{
	this->setMinimumHeight(height);
}

控制器和数据结构

Controller主要用于控制数据结构,添加和删除图标等。这里还自定义了一个ItemMimeData用于拖拽图标
enum {BigIcon_Mode = 0, SmallIcon_Mode};
struct IconItemData
{
	QImage  image;
	QString name;
	int mode ;
	IconItemData()
	{
		mode = SmallIcon_Mode;
	}
};

class Controller:public QObject
{
	Q_OBJECT
public:
	Controller(QObject *parent = NULL);
	~Controller();
	void init();
	void addItem(IconItemData* pItem);
	void deleteItem(int index);
	void deleteItem(IconItemData* pItem);
	void changeIconMode(int mode);
	size_t getSize()
	{
		return m_IconDataVec.size();
	}

	IconItemData* getItem(int index);

protected:
	
private:
	vector<IconItemData*>  m_IconDataVec;
};


class ItemMimeData:public QMimeData
{
	Q_OBJECT
public:
	ItemMimeData():QMimeData()
	{
		m_pDragItemList = NULL;
	}

	~ItemMimeData()
	{
		if (m_pDragItemList)
		{
			delete m_pDragItemList;
		}
	}

	void SetDragDatas(QString mimeType , QList<IconItemData*> *pItemList)
	{
		m_format<<mimeType;
		m_pDragItemList = pItemList;
	}

	QStringList formats() const
	{
		return m_format;
	}

	const QList<IconItemData*>* DragItemData() const
	{
		return m_pDragItemList;
	}



protected:

	QVariant retrieveData(const QString &mimetype, QVariant::Type preferredType) const
	{
		if (mimetype == "ItemMimeData")
		{
			return m_pDragItemList;
		}

		else
		{
			 return QMimeData::retrieveData(mimetype, preferredType);  
		}
	}
private:
	QStringList              m_format;
	const QList<IconItemData*> *m_pDragItemList;
};

void Controller::addItem( IconItemData* pItem )
{
	if (pItem)
	{
		m_IconDataVec.push_back(pItem);
	}
}

void Controller::deleteItem( int index )
{
	if ((index > 0) && (index < m_IconDataVec.size()))
	{
		vector<IconItemData*>::iterator it = m_IconDataVec.begin();
		it = it + index;
		m_IconDataVec.erase(it);
	}
}

void Controller::deleteItem( IconItemData* pItem )
{
	if (pItem)
	{
		vector<IconItemData*>::iterator it = m_IconDataVec.begin();
		for (it; it != m_IconDataVec.end(); ++it)
		{
			if (pItem == *it)
			{
				m_IconDataVec.erase(it);
				break;
			}
		}
	}
}

IconItemData* Controller::getItem( int index )
{
	if ((index >= 0) && (index < m_IconDataVec.size()))
	{
		return m_IconDataVec[index];
	}
}

void Controller::init()
{
	for (int i = 0; i < 20; ++i)
	{
		IconItemData *pItem = new IconItemData;
		pItem->name = QString::number(i);
		QString iconPath = QString(":/DragIcon/Resources/%1.jpg").arg(i);
		QFile Iconfile(iconPath);
		if (Iconfile.exists())
		{
			pItem->image = QImage(iconPath);
			m_IconDataVec.push_back(pItem);
		}
		else
		{
			delete pItem;
		}
	}
}

Controller::Controller( QObject *parent /*= NULL*/ ):QObject(parent)
{
	//init();
}

Controller::~Controller()
{

}

void Controller::changeIconMode( int mode )
{
	for (int i = 0; i < m_IconDataVec.size(); ++i)
	{
		m_IconDataVec[i]->mode = mode;
	}
}

图标部件

IconItemWidget主要由一个label显示图标,lineEdit来显示名称
class ItemNameLineEdit:public QLineEdit
{
	Q_OBJECT
public:
	ItemNameLineEdit(QWidget *parent = NULL);
	~ItemNameLineEdit();
protected:
	void mouseDoubleClickEvent ( QMouseEvent * event );
	private slots:
		void finishEditSlot();
};

class IconItemWidget:public QWidget
{
	Q_OBJECT
public:
	IconItemWidget(IconItemData *pData,QWidget *parent = NULL);
	~IconItemWidget();

	void unSelectedItem()
	{
		m_selected = false;
	}
	void SelectItem()
	{
		m_selected = true;
	}

	IconItemData *getData()
	{
		return m_pItemData;
	}
protected:
	void resizeEvent ( QResizeEvent * event ) ;
	void paintEvent ( QPaintEvent * event ) ;
private:
	QLabel              *m_pImage;
	ItemNameLineEdit    *m_pNameLEdit;
	IconItemData        *m_pItemData;
	bool                 m_selected;
	QPoint               m_mousePressPos;
};

IconItemWidget::IconItemWidget( IconItemData *pData,QWidget *parent /*= NULL*/ ):QWidget(parent),m_pItemData(pData)
{
	m_selected = false;
	m_pImage = new QLabel(this);
	m_pNameLEdit = new ItemNameLineEdit(this);
	m_pNameLEdit->setAlignment(Qt::AlignCenter);
	QSize imageSize;
	QPixmap pixmap ;
	if (m_pItemData->mode == BigIcon_Mode)
	{
		pixmap = QPixmap::fromImage(m_pItemData->image).scaled(QSize(100,100),Qt::KeepAspectRatio);
		 imageSize = pixmap.size();
		
		m_pImage->setPixmap(pixmap);
		m_pNameLEdit->setText(m_pItemData->name);
		const int spacing = 5;
		int nameheight = 15;
		m_pImage->setGeometry(spacing,spacing,imageSize.width(),imageSize.height());
		m_pNameLEdit->setGeometry(spacing,spacing + imageSize.height(),imageSize.width(),nameheight);
		this->setFixedSize(QSize(imageSize.width() + 10,imageSize.height() + 25));
	} 
	else if (m_pItemData->mode == SmallIcon_Mode)
	{
		pixmap = QPixmap::fromImage(m_pItemData->image).scaled(QSize(80,80),Qt::KeepAspectRatio);
		 imageSize = pixmap.size();
		m_pImage->setPixmap(pixmap);
		m_pNameLEdit->setText(m_pItemData->name);
		const int spacing = 5;
		int nameheight = 15;
		m_pImage->setGeometry(spacing,spacing,imageSize.width(),imageSize.height());
		m_pNameLEdit->setGeometry(spacing,spacing + imageSize.height(),imageSize.width(),nameheight);
		this->setFixedSize(QSize(imageSize.width() + 10,imageSize.height() + 25));
	}
	
	
}

IconItemWidget::~IconItemWidget()
{

}

void IconItemWidget::resizeEvent( QResizeEvent * event )
{
	QWidget::resizeEvent(event);
}

void IconItemWidget::paintEvent( QPaintEvent * event )
{
	if (m_selected)
	{
		//添加选中样式边框
		this->setStyleSheet("QLabel{border-width: 2px;border-style: solid;border-color: blue;}");
	}
	else
	{
		//取消选中样式
		this->setStyleSheet("");
	}
	QWidget::paintEvent(event);
}

void ItemNameLineEdit::mouseDoubleClickEvent( QMouseEvent * event )
{
	this->setReadOnly(false);
}

ItemNameLineEdit::ItemNameLineEdit( QWidget *parent /*= NULL*/ ):QLineEdit(parent)
{
	this->setContextMenuPolicy(Qt::NoContextMenu);   //禁用默认右键菜单
	this->setReadOnly(true);
	connect(this ,SIGNAL(editingFinished ()),this,SLOT(finishEditSlot()));
}

ItemNameLineEdit::~ItemNameLineEdit()
{

}

void ItemNameLineEdit::finishEditSlot()
{
	this->setReadOnly(true);
}

布局部件

class MainWidget:public QWidget
{
	Q_OBJECT
public:
	MainWidget(QWidget *parent = NULL);
	~MainWidget();
	
	void init();

private slots:
	void bigModeSlot();
	void smallModeSlot();
	void reLayoutIconSlot();
	void deleteItemSlot();

protected:
	void mousePressEvent ( QMouseEvent * event );
	void mouseMoveEvent ( QMouseEvent * event );
	void mouseReleaseEvent(QMouseEvent *event);
	void dragEnterEvent ( QDragEnterEvent * event );
	void dragLeaveEvent ( QDragLeaveEvent * event );
	void dragMoveEvent ( QDragMoveEvent * event ) ;
	void dropEvent(QDropEvent *event);

	void resizeEvent ( QResizeEvent * event );
	void paintEvent ( QPaintEvent * event );
	QRect GetItemRect( int index);
	void clear();
	void performDrag();
	void SelectItem();
	bool HitTest(QMouseEvent * event);
	bool isInVector(IconItemWidget* pItem);
signals:
	void heightChangeSignal(int height);
private:
	int                         iconMode;
	Controller                 *m_pController;
	vector<IconItemWidget*>     m_ItemVec;
	QPushButton             *m_pAddButton;
	QPoint               m_mousePressPos;
	vector<IconItemWidget*>  m_selectItemVec;
	QPoint               m_mousePos;                
};

MainWidget::MainWidget( QWidget *parent /*= NULL*/ ):QWidget(parent),iconMode(SmallIcon_Mode)
{
	this->setAcceptDrops(true);
	m_pController = new Controller(this);
	//init();
	this->setMinimumWidth(100);
}

MainWidget::~MainWidget()
{

}

void MainWidget::init()
{
	m_pController->init();
	for (int i = 0; i < m_pController->getSize(); ++i)
	{
		IconItemWidget *pItemWidget = new IconItemWidget(m_pController->getItem(i),this);
		m_ItemVec.push_back(pItemWidget);
	}
}
//获取每个图标应该布局的位置
 QRect MainWidget::GetItemRect( int index )
{
	if (index < 0 || index > m_ItemVec.size())
	{
		return QRect();
	}
	const int spacing = 5;
	int width = this->width();
	int height = this->height();

	int itemWidth = m_ItemVec[index]->width();
	int itemHeight = m_ItemVec[index]->height();
	int colCount = width / (itemWidth + spacing );
	int rowCount = height / (itemHeight + spacing);
	int row = index / colCount;
	int col = index % colCount;
	int xPos = col * (itemWidth + spacing );
	int yPos = row * (itemHeight + spacing);
	return QRect(xPos,yPos,itemWidth,itemHeight);
}

 void MainWidget::resizeEvent( QResizeEvent * event )
 {
	 //改变大小了要重新布局
	 for (int i = 0; i < m_ItemVec.size(); ++i)
	 {
		 QRect rect = GetItemRect(i);
		 if (i == m_ItemVec.size() - 1)
		 {
			 this->setMinimumHeight(rect.y() + 20);
			 emit heightChangeSignal(this->height());
		 }
		
		 m_ItemVec[i]->setGeometry(rect);
	 }
	 QWidget::resizeEvent(event);
 }

 void MainWidget::paintEvent( QPaintEvent * event )
 {
	 if (m_mousePos.x() == 0 && m_mousePos.y() == 0)
	 {
		 return;
	 }
	 //画红色选框
	 QRect rect(m_mousePressPos,m_mousePos);
	 QPainter painter(this);
	 painter.setPen(Qt::red);
	 painter.drawRect(rect);
	 update();
	 QWidget::paintEvent(event);
 }

 void MainWidget::mousePressEvent( QMouseEvent * event )
 {
	 m_mousePressPos = event->pos();
	 //点击空白处则情况选中,
	 //如果m_selectItemVec大小为1,则也要清空下面再另外选中
	 //右键单击也要清空m_selectItemVec
	 if (!HitTest(event) || (m_selectItemVec.size() == 1) ||Qt::RightButton == event->button())   
	 {
		for (int i = 0; i < m_selectItemVec.size(); ++i)
		{
			m_selectItemVec[i]->unSelectedItem();
		}
		m_selectItemVec.clear();
	}
	
	 for (int i = 0; i < m_ItemVec.size(); ++i)
	 {
		 QRect rect = GetItemRect(i);
		 if (rect.contains(event->pos()) && (!isInVector(m_ItemVec[i])))  //图标尚未被选中则添加到m_selectItemVec
		 {
			 m_selectItemVec.push_back(m_ItemVec[i]);
			 m_ItemVec[i]->SelectItem();
		 }
	 }

	 QWidget *pWidget = QApplication::focusWidget();   //如果正在编辑名称,点击别的地方可以结束编辑
	 if (pWidget)
	 {
		 pWidget->clearFocus();
	 }

	 //右键菜单
	 if (Qt::RightButton == event->button())
	 {
		 QMenu *pMenu = new QMenu(this);
		 QAction *pBigModeAct = new QAction(tr("大图标"),pMenu);
		 QAction *pSmallModeAct = new QAction(tr("小图标"),pMenu);
		 QAction *pDeleteAct = new QAction(tr("删除"),pMenu);
		  if (m_selectItemVec.size() > 0)   //有选中的则弹出删除菜单
		  {
			   pMenu->addAction(pDeleteAct);
			  connect(pDeleteAct,SIGNAL(triggered()),this,SLOT(deleteItemSlot()));
		  }
		  else
		  {
			  //点击空白处则可切换图标模式
			  pMenu->addAction(pBigModeAct);
			  pMenu->addAction(pSmallModeAct);
			  connect(pBigModeAct,SIGNAL(triggered()),this,SLOT(bigModeSlot()));
			  connect(pSmallModeAct,SIGNAL(triggered()),this,SLOT(smallModeSlot()));
		  }
		 
		 pMenu->exec(event->globalPos());
		 delete pMenu;
	 }
	 QWidget::mousePressEvent(event);
 }

 //大图标模式
 void MainWidget::bigModeSlot()
 {
	 m_pController->changeIconMode(BigIcon_Mode);
	 reLayoutIconSlot();
	  this->update();
 }
 //小图标模式
 void MainWidget::smallModeSlot()
 {
	  m_pController->changeIconMode(SmallIcon_Mode);
	   reLayoutIconSlot();
	   this->update();
 }

 void MainWidget::reLayoutIconSlot()
 {
	 clear();    //先清除
	 for (int i = 0; i < m_pController->getSize(); ++i)
	 {
		 //重新生成图标
		 IconItemWidget *pItemWidget = new IconItemWidget(m_pController->getItem(i),this);
		 m_ItemVec.push_back(pItemWidget);
	 }
	 for (int i = 0; i < m_ItemVec.size(); ++i)
	 {
		 QRect rect = GetItemRect(i);
		 m_ItemVec[i]->setGeometry(rect);
		 m_ItemVec[i]->show();             //重新生成,布局图标必须show才能显示
	 }
	 this->repaint();
 }

 void MainWidget::clear()
 {
	 qDeleteAll(m_ItemVec);
	 m_ItemVec.clear();
 }

 void MainWidget::mouseMoveEvent( QMouseEvent * event )
 {
	 if (event->buttons() & Qt::LeftButton && (m_selectItemVec.size() > 0))
	 {
		 if (( m_mousePressPos - event->pos()).manhattanLength() > QApplication::startDragDistance())
		 {
			 performDrag();
		 }
	 }
	 else
	 {
		 m_mousePos = event->pos();
	 }
	 QWidget::mouseMoveEvent(event);
 }

 void MainWidget::mouseReleaseEvent( QMouseEvent *event )
 {
	 if (m_mousePos.x() == 0 && m_mousePos.y() == 0)
	 {
		 return;
	 }
	 else 
	 {
		 //release鼠标再进行选择
		 SelectItem();
	 }
	 m_mousePos = QPoint();
	 QWidget::mouseReleaseEvent(event);
 }

 void MainWidget::dragEnterEvent( QDragEnterEvent * event )
 {
	 const ItemMimeData *pMimeData = (const ItemMimeData*)event->mimeData();
	 const QList<IconItemData*>* plist = pMimeData->DragItemData();
	 if (plist)
	 {
		 event->accept();
	 }
 }

 void MainWidget::dragLeaveEvent( QDragLeaveEvent * event )
 {

 }

 void MainWidget::dragMoveEvent( QDragMoveEvent * event )
 {
	 event->accept();
 }

 void MainWidget::performDrag()
 {
	 QDrag  *pDrag = new QDrag(this);
	 ItemMimeData *pData = new ItemMimeData;
	  QList<IconItemData*> *plist = new QList<IconItemData*>;
	 for (int i = 0; i < m_selectItemVec.size(); ++i)
	 {
		 plist->append(m_selectItemVec[i]->getData());
	 }
	 pData->SetDragDatas("ItemMimeData",plist);
	 pDrag->setMimeData(pData);

	 QPixmap pixmap = QPixmap::fromImage(m_selectItemVec[0]->getData()->image).scaled(50,50,Qt::KeepAspectRatio);
	 pDrag->setPixmap(pixmap);
	 pDrag->exec(Qt::CopyAction);
	 //delete m_selectItemVec[0];
 }

 void MainWidget::dropEvent( QDropEvent *event )
 {
	 const ItemMimeData *pMimeData = (const ItemMimeData*)event->mimeData();
	 const QList<IconItemData*>* plist = pMimeData->DragItemData();
	 if (plist)
	 {
		 for (int i = 0; i < plist->size(); ++i)
		 {
			 m_pController->addItem(plist->at(i));
		 }
		 reLayoutIconSlot();
		 event->accept();
	 }

 }

 void MainWidget::deleteItemSlot()
 {
	 //删除再重新布局
	 for (int i = 0; i < m_selectItemVec.size(); ++i)
	 {
		 m_pController->deleteItem(m_selectItemVec[i]->getData());
	 }
	 reLayoutIconSlot();
 }


 //框选多个图标
 void MainWidget::SelectItem()
 {
	  QRect rect(m_mousePressPos,m_mousePos);
	  for (int i = 0; i < m_ItemVec.size(); ++i)
	  {
		  QPoint centerPos = GetItemRect(i).center();
		  if (rect.contains(centerPos))
		  {
			  m_ItemVec[i]->SelectItem();
			  m_selectItemVec.push_back(m_ItemVec[i]);
		  }
	  }
 }

 //有点击图标则返回true,否则返回false
 bool MainWidget::HitTest( QMouseEvent * event )
 {
	 for (int i = 0; i < m_ItemVec.size(); ++i)
	 {
		 QRect rect = GetItemRect(i);
		 if (rect.contains(event->pos()))
		 {
			return true;
		 }
	 }
	 return false;
 }
 //检查图标是否已经被选中
 bool MainWidget::isInVector(IconItemWidget* pItem )
 {
	 for (int i = 0; i < m_selectItemVec.size(); ++i)
	 {
		 if (m_selectItemVec[i] == pItem)
		 {
			 return true;
		 }
	 }
	 return false;
 }


结果截图;

部件之间图标拖拽_第1张图片

你可能感兴趣的:(qt)