您的位置:首页 > 编程语言 > Qt开发

Qt实现QQ好友下拉列表(用QListView实现,所以还得定义它的Model)

2016-02-01 18:51 573 查看
偶然发现Qt有个控件可以实现下拉列表,所以就试着实现一下类似QQ面板的下拉列表,这里主要实现几个功能:

1.可以删除列表中图标

2.可以像qq一样的,把某个分组下的图标转移到另外的分组

3.添加分组

代码里写了注释了,这里就不重复了,下面直接看代码吧。

自定义的数据模型

ListModel继承了QAbstractListModel,主要是实现要显示的数据结构。用的是model/view的三层结构,这样好拆分

[cpp] view plain copy

struct ListItemData

{

QString iconPath;

QString Name;

};

class ListModel:public QAbstractListModel

{

Q_OBJECT

public:

ListModel(QObject *parent = NULL);

~ListModel();

void init();

void addItem(ListItemData *pItem);

QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;

int rowCount ( const QModelIndex & parent = QModelIndex() ) const;

void deleteItem(int index);

ListItemData* getItem(int index );

protected:

private:

vector<ListItemData*> m_ItemDataVec;

};

[cpp] view plain copy

<pre name="code" class="cpp">ListModel::ListModel( QObject *parent /*= NULL*/ ):QAbstractListModel(parent)

{

init();

}

ListModel::~ListModel()

{

}

QVariant ListModel::data( const QModelIndex & index, int role /*= Qt::DisplayRole */ ) const

{

if (index.row() > m_ItemDataVec.size())

{

return QVariant();

}

else

{

switch (role)

{

case Qt::DisplayRole:

{

return m_ItemDataVec[index.row()]->Name;

}

break;

case Qt::DecorationRole:

{

return QIcon(m_ItemDataVec[index.row()]->iconPath);

}

break;

case Qt::SizeHintRole:

{

return QSize(10,50);

}

}

}

return QVariant();

}

int ListModel::rowCount( const QModelIndex & parent /*= QModelIndex() */ ) const

{

return m_ItemDataVec.size();

}

void ListModel::init()

{

for (int i = 1; i < 26; ++i)

{

ListItemData *pItem = new ListItemData;

pItem->Name = QString::number(i);

pItem->iconPath = QString(":/QQPanel/Resources/%1.jpg").arg(i);

QFile Iconfile(pItem->iconPath);

if (Iconfile.exists())

{

m_ItemDataVec.push_back(pItem);

}

}

}

void ListModel::deleteItem( int index )

{

vector<ListItemData*>::iterator it = m_ItemDataVec.begin();

m_ItemDataVec.erase(it + index);

}

void ListModel::addItem( ListItemData *pItem )

{

if (pItem)

{

this->beginInsertRows(QModelIndex(),m_ItemDataVec.size(),m_ItemDataVec.size() + 1);

<span style="white-space:pre"> </span>m_ItemDataVec.push_back(pItem);

<span style="white-space:pre"> </span>this->endInsertRows();

}

}

ListItemData* ListModel::getItem( int index )

{

if (index > -1 && index < m_ItemDataVec.size())

{

return m_ItemDataVec[index];

}

}

</pre><br>

<br>

<pre></pre>

<h1><a name="t1"></a><br>

</h1>

<h1><a name="t2"></a>自定义的列表</h1>

<div>这个类才是重点,因为这里实现了删除和转移图标的几个重要的函数。</div>

<pre name="code" class="cpp">class MyListView:public QListView

{

Q_OBJECT

public:

MyListView(QWidget *parent = NULL);

~MyListView();

void setListMap(map<MyListView*,QString> *pListMap);

void addItem(ListItemData *pItem);

protected:

void contextMenuEvent ( QContextMenuEvent * event );

private slots:

void deleteItemSlot(bool bDelete);

void moveSlot(bool bMove);

private:

int m_hitIndex;

ListModel *m_pModel;

////记录分组和分组名字的映射关系,这个值跟QQPanel类中的映射组的值保持一致

//这里还有一个用处就是在弹出的菜单需要分组的名称

map<MyListView*,QString> *m_pListMap;

//记录每个菜单项对应的列表,才能知道要转移到那个分组

map<QAction*,MyListView*> m_ActionMap;

};</pre><br>

<pre name="code" class="cpp">MyListView::MyListView( QWidget *parent /*= NULL*/ ):QListView(parent)

{

m_hitIndex = -1;

m_pModel = new ListModel;

this->setModel(m_pModel);

m_pListMap = NULL;

}

MyListView::~MyListView()

{

}

void MyListView::contextMenuEvent( QContextMenuEvent * event )

{

int hitIndex = this->indexAt(event->pos()).column();

if (hitIndex > -1)

{

QMenu *pMenu = new QMenu(this);

QAction *pDeleteAct = new QAction(tr("删除"),pMenu);

pMenu->addAction(pDeleteAct);

connect(pDeleteAct,SIGNAL(triggered (bool)),this,SLOT(deleteItemSlot(bool)));

QMenu *pSubMenu = NULL;

map<MyListView*,QString>::iterator it = m_pListMap->begin();

for (it;it != m_pListMap->end();++it)

{

if (!pSubMenu)

{

pSubMenu = new QMenu(tr("转移联系人至") ,pMenu);

pMenu->addMenu(pSubMenu);

}

if (it->first != this)

{

QAction *pMoveAct = new QAction( it->second ,pMenu);

//记录菜单与分组的映射,在moveSlot()响应时需要用到。

m_ActionMap.insert(pair<QAction*,MyListView*>(pMoveAct,it->first));

pSubMenu->addAction(pMoveAct);

connect(pMoveAct,SIGNAL(triggered (bool)),this,SLOT(moveSlot(bool)));

}

}

pMenu->popup(mapToGlobal(event->pos()));

}

}

void MyListView::deleteItemSlot( bool bDelete )

{

int index = this->currentIndex().row();

if (index > -1)

{

m_pModel->deleteItem(index);

}

}

void MyListView::setListMap( map<MyListView*,QString> *pListMap )

{

m_pListMap = pListMap;

}

void MyListView::addItem( ListItemData *pItem )

{

m_pModel->addItem(pItem);

}

void MyListView::moveSlot( bool bMove )

{

QAction *pSender = qobject_cast<QAction*>(sender());

if (pSender)

{

//根据点击的菜单,找到相应的列表,然后才能把图标转移过去

MyListView *pList = m_ActionMap.find(pSender)->second;

if (pList)

{

int index = this->currentIndex().row();

ListItemData *pItem = m_pModel->getItem(index);

pList->addItem(pItem);

//添加到别的分组,就在原来的分组中删除掉了

m_pModel->deleteItem(index);

}

}

//操作完了要把这个临时的映射清空

m_ActionMap.clear();

}

</pre><br>

<h1><a name="t3"></a>自定义的主控件</h1>

[cpp] view plain copy

class QQPanel : public QWidget

{

Q_OBJECT

public:

QQPanel(QWidget *parent = 0, Qt::WFlags flags = 0);

~QQPanel();

protected:

void contextMenuEvent ( QContextMenuEvent * event );

protected slots:

void addGroupSlot(bool addgroup);

private:

QToolBox *m_pBox;

map<MyListView*,QString> *m_pListMap; //记录分组和分组名字的映射关系,好在转移图标时知道转移到那个分组

};

[cpp] view plain copy

QQPanel::QQPanel(QWidget *parent, Qt::WFlags flags)

: QWidget(parent, flags)

{

m_pBox = new QToolBox(this);

m_pListMap = new map<MyListView*,QString>();

MyListView *pListView = new MyListView(this);

pListView->setViewMode(QListView::ListMode);

pListView->setStyleSheet("QListView{icon-size:40px}");

m_pBox->addItem(pListView,tr("我的好友"));

m_pListMap->insert(pair<MyListView*,QString>(pListView,tr("我的好友")));

MyListView *pListView1 = new MyListView(this);

pListView1->setViewMode(QListView::ListMode);

pListView1->setStyleSheet("QListView{icon-size:40px}");

m_pBox->addItem(pListView1,tr("陌生人"));

m_pListMap->insert(pair<MyListView*,QString>(pListView1,tr("陌生人")));

pListView->setListMap(m_pListMap);

pListView1->setListMap(m_pListMap);

m_pBox->setFixedWidth(150);

m_pBox->setMinimumHeight(500);

this->setMinimumSize(200,500);

//ui.setupUi(this);

}

QQPanel::~QQPanel()

{

}

void QQPanel::contextMenuEvent( QContextMenuEvent * event )

{

QMenu *pMenu = new QMenu(this);

QAction *pAddGroupAct = new QAction(tr("添加分组"),pMenu);

pMenu->addAction(pAddGroupAct);

connect(pAddGroupAct,SIGNAL(triggered (bool)),this,SLOT(addGroupSlot(bool)));

pMenu->popup(mapToGlobal(event->pos()));

}

void QQPanel::addGroupSlot( bool addgroup )

{

QString name = QInputDialog::getText(this,tr("输入分组名"),tr(""));

if (!name.isEmpty())

{

MyListView *pListView1 = new MyListView(this);

pListView1->setViewMode(QListView::ListMode);

pListView1->setStyleSheet("QListView{icon-size:40px}");

m_pBox->addItem(pListView1,name);

m_pListMap->insert(pair<MyListView*,QString>(pListView1,name));

}

//要确保每个MyListView钟的m_pListMap都是一致的,不然就会有错了。

//因为弹出的菜单进行转移的时候需要用到

map<MyListView*,QString>::iterator it = m_pListMap->begin();

for (it; it != m_pListMap->end(); ++it)

{

MyListView* pList = it->first;

pList->setListMap(m_pListMap);

}

}

运行结果





由以上两个截图显示,我的好友和陌生人的个有5个图标





以上两个截图显示,把陌生人中图标5转移到我的好友里





以上两个截图,显示添加了一个分组,黑名单,因为我默认列表在创建时都有相同的5个图标







以上三个截图显示了把黑名单里的图标5转移到了我的好友分组里了

当然这个程序算是比较简单的。还不能真正的跟QQ的面板相比,还不能把所有的分组都收起来。以后再慢慢研究怎么实现了,
http://blog.csdn.net/hai200501019/article/details/10283553
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: