【Qt实用技巧】实现群聊@群成员-选择群成员

173 阅读3分钟

📒博客首页:何名取 的个人主页 - 文章 - 掘金 (juejin.cn)
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
❤️期待一起交流!
🙏作者水平很有限,如果发现错误,求告知,多谢!
🌺有问题可私信交流!!!


前言

前面的文章中已经实现了输入@符号弹出可以跟随文字显示的窗口,窗口中简单放置了一行文字(作者的笔名何名取)。本节则来模拟一下微信中输入@弹出群成员列表,并且可以进行群成员的选择。

动画4.gif

按键过滤

在输入框与弹出的群成员列表交互过程中会产生一系列的按键事件。如上面动图中显示的那样,弹出群成员列表后可以按下键盘上的上下键进行选择成员,按下回车键确定选择,还有其他的比如空格键等。因此需要对按键事件进行过滤,并且实现相应按键事件的响应功能。

在Qt中可以重写eventFilter事件过滤函数来实现我们所需的按键过滤。

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if(event->type() == QEvent::KeyPress)   //键盘按下事件
    {
        if(watched == ui->textEdit)         //事件发送者为输入框
        {
            QKeyEvent *k = static_cast<QKeyEvent *>(event);
            if(k->key() == Qt::Key_Up)
            {
                if(w->isVisible())
                {
                    w->keySelectItem(false);
                    return true;
                }
                else
                    return QWidget::eventFilter(watched,event);
            }
            else if(k->key() == Qt::Key_Down)
            {
                if(w->isVisible())
                {
                    w->keySelectItem(true);
                    return true;
                }
                else
                    return QWidget::eventFilter(watched,event);
            }
            else if(k->key() == Qt::Key_Space)
            {
                if(w->isVisible())
                {
                    w->close();
                    return true;
                }
                else
                    return QWidget::eventFilter(watched,event);
            }
            else if(k->key() == Qt::Key_Return || k->key() == Qt::Key_Enter)
            {
                if(w->isVisible())
                {
                    QString name = w->getSelectName();
                    receiveName(name);
                    w->close();
                    return true;
                }
                else
                    return QWidget::eventFilter(watched,event);
            }
            else if(k->key() == Qt::Key_Backspace)
            {
                if(w->isVisible())
                {
                    w->close();
                    return true;
                }
                else
                    return QWidget::eventFilter(watched,event);
            }
            else
                return QWidget::eventFilter(watched,event);
        }
        else
            return QWidget::eventFilter(watched,event);
    }
    else
        return QWidget::eventFilter(watched,event);
}

需要注意的一点是重写完成eventFilter事件过滤函数后必须进行注册才可以产生过滤。

ui->textEdit->installEventFilter(this);

修改弹出窗口

上节并没有对弹出的窗口进行过多操作,本节将给窗口中添加QListWidget列表作为可选择的群成员列表。

按键选择

通过上下按键来进行当前列表项的选择。

void Form::keySelectItem(bool flag)
{
    int row = ui->listWidget->currentRow();
    if(flag)
    {
        if(row + 1 >= ui->listWidget->count())
            ui->listWidget->setCurrentRow(0);
        else
            ui->listWidget->setCurrentRow(row + 1);
    }
    else
    {
        if(row - 1 < 0)
            ui->listWidget->setCurrentRow(ui->listWidget->count() - 1);
        else
            ui->listWidget->setCurrentRow(row - 1);
    }
}

设置成员添加规则

我使用了QMap来储存三个简单的字符串来模拟群成员选项。

    users["hemingqu"] = "何名取";
    users["juejin"] = "掘金";
    users["2023"] = "2023";

之后为列表中添加上这几个成员,并且设置输入时的匹配规则。

void Form::setFilter(QString filter)
{
    ui->listWidget->clear();
    for (int i = 0; i < users.count(); ++i) {
        addItem(users.keys().at(i),users.values().at(i),filter);
    }
    if(ui->listWidget->count() == 0)
    {
        close();
        return;
    }

    ui->listWidget->setCurrentRow(0);
    this->setAttribute(Qt::WA_ShowWithoutActivating);
    ui->listWidget->setFocus();
}

void Form::addItem(QString userId, QString name, QString filter)
{
    if(!userId.contains(filter) && !name.contains(filter))
        return;

    QListWidgetItem *item = new QListWidgetItem(ui->listWidget);
    item->setFont(QFont("",14));
    item->setText(name);
    ui->listWidget->addItem(item);
}

成员信息获取

最后在弹窗中被选择的信息需要一个可以获取函数来进行传递。

QString Form::getSelectName()
{
    QListWidgetItem *item = ui->listWidget->currentItem();
    if(item == nullptr)
        return "";
    return item->text();
}

接收信息响应

在主窗口中要将传递的成员信息进行接收,并插入输入框中展示。

void MainWindow::receiveName(QString name)
{
    while(!ui->textEdit->textCursor().block().text().endsWith("@"))
        ui->textEdit->textCursor().deletePreviousChar();
    if(ui->textEdit->textCursor().block().text().endsWith("@"))
    ;
    else
        ui->textEdit->textCursor().insertText("@");
    ui->textEdit->textCursor().insertText(name);
}

完整代码获取