又到周末了,尝试实现一个图标拖拽的小程序;主要实现的功能有:
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;
}