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