Qt實現模擬微信聯繫人列表

聯繫人列表主要由兩部分組成,每個聯繫人的狀態消息框和一個列表組成,因此,我們用QListWidget和自定義的item來實現這個列表。

1、自定義message item

如圖:
在這裏插入圖片描述
一個item由頭像、暱稱、最近的一條消息、最近一條消息的時間和關閉按鈕組成,因此我們首先用designer按照需要的東西選擇合適的控件進行繪製界面。
界面繪製完成之後,就需要完成界面所需要的一些槽函數,在這邊,我們應該有一個主題思想是需要確定的,就是每個item所需要的數據由自己管理,這樣,在管理這些數據的時候就會比較方便, 會避免在外界管理所有item的數據而形成的比較龐大的數據結構。
實現槽函數的方式有很多,這兒我們採用自定義屬性的方式來確定一些需要的數據。題外:Qt的每個原生控件都有一些被 Q_PROPERTY qproperty- 定義的原始屬性,Q_PROPERTY是一個宏。

# define Q_PROPERTY(...) QT_ANNOTATE_CLASS(qt_property, __VA_ARGS__)

我們也使用這種方法來添加一些自定義item的屬性。如下:

class MsgItem : public QWidget
{    Q_OBJECT
     Q_PROPERTY(QString msg READ msg WRITE setMsg DESIGNABLE true)
 public:
    explicit MsgItem(QWidget *parent = 0);
     ~MsgItem();  
 private:
 	Ui::MsgItem *ui;
 };

使用這種自定義屬性的方式需要實現的公有方法的格式是比較固定的。如下:

QString msg() const;
void setMsg(const QString& msg);

按照上面的方式實現其餘的方法。
實現的列表點擊每個item的時候會有選中的效果,這種選中的效果有兩種實現方式,一種是最正常的方式,也就是借用QListWidget的itemClicked(QListWidgetItem*)信號來按部就班的實現;另一種是通過集成QWidget的mouse事件來模擬選中的效果。這個例子中兩種方式都有涉獵。最終的item類定義如下:

class MsgItem : public QWidget
{    Q_OBJECT
     //可按照下面的方法自己添加需要的功能
     Q_PROPERTY(QString msg READ msg WRITE setMsg DESIGNABLE true)
     Q_PROPERTY(QString header READ header WRITE setHeader DESIGNABLE true)
     Q_PROPERTY(QString name READ name WRITE setName DESIGNABLE true)
     Q_PROPERTY(QString uuid READ uuid WRITE setUuid DESIGNABLE true)
     Q_PROPERTY(QString datetime READ datetime WRITE setDatetime DESIGNABLE true)
     Q_PROPERTY(int count READ count WRITE setCount DESIGNABLE true)

public:
    explicit MsgItem(QWidget *parent = 0);
     ~MsgItem();

    QString msg() const;
    void setMsg(const QString& msg);

    QString header() const;
    void setHeader(const QString& header);

    QString uuid() const
    {
        return m_uuid;
    }
    void setUuid(const QString& uuid)
    {
        m_uuid = uuid;
    }

    QString name() const;
    void setName(const QString& name);

    QString datetime() const;
    void setDatetime(const QString& datetime);

    int count() const;
    void setCount(const int count);

    void setData( const QString &msg,
                        const QString& nick,
                        const QString& header,
                        const QString& name,
                        const QString& time );

    void selected(bool selected);

protected:
     virtual void mousePressEvent( QMouseEvent *event );


private slots:
     void on_btnDeleteClicked();

signals:
     void signal_selected(MsgItem*);
     void signal_delete(QWidget*);

private:
     Ui::MsgItem *ui;
     QString m_header{""};
     QString m_uuid{""};
};

其中的實現也比較簡單,就是簡單的設置一些界面的信息顯示。我們看一下選中的效果實現:

void MsgItem::selected(bool selected)
{
    ui->widgetMain->setStyleSheet(selected ? 
    QString("QWidget#widgetMain{ background-color: #F2F2F2; border-bottom: 1px solid #F2F2F2;}")
  : QString("QWidget#widgetMain{ background-color: #FFFFFF; border-bottom: 1px solid #F2F2F2;}" ));
    ui->btnClose->setVisible(selected);
    setCount(0);
}

選中的效果是通過設置不同的qss來實現。

2、容器的實現

容器的實現基本上沒什麼比較注重的地方,使用QListWidget的原始功能就能夠實現。爲了方便設置選中的效果的切換,我們需要定義一個成員變量來記錄當前的item,當進行切換時,先設置上一個爲未選中,再設置下一個爲選中即可。

因爲item是自定義的,因此創建item的時候需要將自定義的item通過setItemWidget(QListWidgetItem*, QWidget*)方法加載到原始的item上。如下所示:

void ListTemplate::AddWidgetMsgItem()
{
    auto pMsgItem = new MsgItem();
    QListWidgetItem *item = new QListWidgetItem;
    item->setSizeHint( QSize(360, 70));
    pMsgItem->setCount(99);
    ui->listWidget->addItem(item);
    ui->listWidget->setItemWidget(item, pMsgItem);

    connect(pMsgItem, &MsgItem::signal_selected, this, &ListTemplate::slot_selected);
    connect(pMsgItem, &MsgItem::signal_delete, this, &ListTemplate::slot_delete);
}

這邊將MsgItem的創建操作放在函數體內是爲了方便測試,通過函數參數的方式傳遞進來在實際使用過程中會比較方便。

選中效果的實現也比較簡單,下面我們主要用一種方式實現,另一種方式在源代碼中有,後面有鏈接。

//第一種選中的實現方式
void ListTemplate::slot_selected(MsgItem *pWidget)
{
    if(Q_NULLPTR == pWidget)
    {
        return;
    }
    if(Q_NULLPTR != m_pCurrentItem)
    {
         m_pCurrentItem->selected(false);
    }
	//先設置當前的爲不選中即false狀態,然後將點擊的設置爲選中狀態,當前指針指向點擊的item
    pWidget->selected(true);
    m_pCurrentItem = pWidget;
}

tem的刪除也是比較簡單的,但是在刪除的時候別忘了資源回收。

void ListTemplate::slot_delete(QWidget* pWidget)
{
    delete pWidget;
    pWidget = Q_NULLPTR;
    QListWidgetItem *pItem = ui->listWidget->takeItem(ui->listWidget->currentRow());
    m_pCurrentItem = Q_NULLPTR;
    m_pCurrent = Q_NULLPTR;
}

這邊有一個注意的點,假設信號槽的連接中沒有參數,我們需要手動來獲取加載在QListWidgetItem上的MsgItem,需要注意的是應該先使用iremWidget()來獲取,再使用takeItem卸載QListWidgetItem,否則會出現取不到QWidget的情況。具體可以參考:
Qt 中 QListWidget 獲取itemWidget() 失敗
看下最終效果:
在這裏插入圖片描述
源碼地址:https://gitee.com/Gqian_com/customcomponent

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章