核心提示:自己增加了需要的一些功能:实现了listview的delegate文字可以鼠标选择并复制、接受键盘ctrl+c复制,item的删除,鼠标上滑到最顶端时加载更多item,摒弃了互动聊天方式,只用于推送,...
自己增加了需要的一些功能:实现了listview的delegate文字可以鼠标选择并复制、接受键盘ctrl+c复制,item的删除,鼠标上滑到最顶端时加载更多item,摒弃了互动聊天方式,只用于推送,若需要建议参考以上链接
直接贴代码:
import QtQuick 2.6
import QtQuick.Layouts 1.3 import QtQuick.Controls 2.0 Rectangle { id: root color: "#f5f5f5" function add_message(timetext,issame,text,who,istip,type,id) { if(text.length <= 0) { return; } listView.model.insert(0, {"content": text, "send": who,"msgTime":timetext,"same":issame,"tip":istip, "send_type": type,"id": id}); //verScrollBar.increase() //滚动条移动到最下面 verScrollBar.setPosition(1.0) } function add_more_message(timetext,issame,text,who,istip,type,id) { if(text.length <= 0) { return; } var count=listView.model.count listView.model.insert(count, {"content": text, "send": who,"msgTime":timetext,"same":issame,"tip":istip, "send_type": type,"id": id}); //verScrollBar.increase() //verScrollBar.setPosition(1.0) } function clearListview() { listView.model.clear() } function re_edit_item(index) { var count=listView.model.count if(count>0){ listView.model.remove(index,1) } } property bool showtip: false function show_tip() { showtip=true } function hide_tip() { showtip=false } ColumnLayout { id:page anchors.fill: parent //接受键盘事件focus必须为true focus: true //由于messageText接受不到键盘事件,定义一个信号 //page接收到ctrl+c使通知messagetext copy signal ctrl_c() Keys.onPressed: { if((event.modifiers===Qt.ControlModifier) && (event.key===Qt.Key_C)){ //发射信号 page.ctrl_c() } event.accepted=true } Rectangle { id:tiprect width: tiptext.implicitWidth+10 height: 30 color: "#f5f5f5" anchors.horizontalCenter: parent.horizontalCenter visible:showtip Label { id: tiptext text: "查看更多消息请前往消息记录" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter color: "#1f61ff" font.family: "微软雅黑" font.pointSize: 9 anchors.fill: parent anchors.margins:0 } } ListView { id: listView Layout.fillWidth: true Layout.fillHeight: true Layout.margins:14 Layout.rightMargin: 0 displayMarginBeginning: 40 displayMarginEnd: 40 verticalLayoutDirection: ListView.BottomToTop spacing:14 model:ListModel{} delegate: Column { anchors.left: parent.left spacing: 14 width: parent.width property bool sendmessage: send property bool sameTime: same //时间 Rectangle { width: timetext.implicitWidth+10 height: timetext.implicitHeight+2 color: tip ? "lightgrey" : "#d1cece" anchors.horizontalCenter: parent.horizontalCenter visible: !same Label { id: timetext text: msgTime verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter color: tip ? "red" : "white" font.family: "微软雅黑" font.pointSize: 9 anchors.fill: parent anchors.margins:0 } } //消息内容 Row { id: messageRow spacing: 6 anchors.left: parent.left visible: !tip //头像 Image { id: avatarLeft height: 36 width: height source: "qrc:/image/touxiang.jpg" } //消息框 Rectangle { width: Math.min(messageText.implicitWidth +14, listView.width -98) height: messageText.implicitHeight + 16 color: send ? "#9dea6a" : "#eeeeee" radius: 3 TextEdit { id: messageText text: content font.family: "华文细黑" //color: "#9dea6a" font.pointSize: 11 anchors.fill: parent anchors.topMargin: 9 anchors.bottomMargin: 7 anchors.rightMargin: 7 anchors.leftMargin: 7 wrapMode: TextEdit.Wrap enabled: true readOnly: true selectByKeyboard: true selectByMouse: true selectedTextColor: "white" persistentSelection:true selectionColor: "#3396FF" //设置选择文本的时候使得不滑动listview Drag.active: text_area.drag.active } //鼠标区域,支持的功能是选择复制和撤销 MouseArea{ id:text_area width: parent.width height: parent.height acceptedButtons: Qt.LeftButton|Qt.RightButton //把拖动的对象设为起父亲,由于一样打,所以使得拖动不会影响界面显示 drag.target: messageText hoverEnabled: true property int _startpos: 0 property int _endpos: 0 property bool canselect: false onClicked: { //三个=为全等于,js语法 if(mouse.button===Qt.RightButton){ //右键按下弹出右键菜单的的时候选择会清空,所以只好重新选一遍 if(_startpos<_endpos){ messageText.select(_startpos-1,_endpos) } else { if(_startpos>_endpos){ messageText.select(_endpos-1,_startpos) } else { messageText.select(_startpos,_endpos) } } //使用mainwindow中的函数 mainwindow.listview_item_clicked(index,id,send_type,messageText.selectedText,messageText.text) } } onEntered: { //连接信号和槽,只有当鼠标进入区域时才响应信号 page.ctrl_c.connect(message_cpoy) } //复制 function message_cpoy(){ messageText.copy() } //鼠标离开,清空选择,解绑信号 onExited: { messageText.deselect() _startpos=0 _endpos=0 page.ctrl_c.disconnect(message_cpoy) } //跟随鼠标进行选择 onMouseXChanged: { if(canselect){ _endpos=messageText.positionAt(mouseX,mouseY) //使开始位置减1,符合视觉效果 if(_startpos<_endpos){ messageText.select(_startpos-1,_endpos) } else { if(_startpos>_endpos){ messageText.select(_endpos-1,_startpos) } else { messageText.select(_startpos,_endpos) } } } } //只有鼠标左键按下时才可以选择 onPressed: { if(mouse.button===Qt.LeftButton){ canselect=true _startpos=messageText.positionAt(mouseX,mouseY) } } //鼠标左键弹起后不可选择 onReleased: { if(mouse.button===Qt.LeftButton){ //messageText.copy() canselect=false } } } } } } ScrollBar.vertical: ScrollBar { id: verScrollBar } //鼠标上滑加载更多数据 onContentYChanged: { //console.log("contenty:"+contentY) //console.log("originy"+originY) var x=contentY-originY if(x==0){ mainwindow.load_more_for_chatwidget(); } } } /*接收cpp发来信号显示的方法 Connections{ target: mywindows onShowmymsg:add_message(arg_1,arg_2,arg_3,arg_4,arg_5) }*/ } } //cpp中的函数:(在cpp中设置上下文属性后可用) //quickwidget载入qml QUrl source("qrc:/myqml/1.qml"); //设置上下文属性c++与qml,使qml能使用c++的Q_INVOKABLE声明的public函数或者public槽函数 ui->quickWidget->rootContext()->setContextProperty("mainwindow",this); //下面此方法目前有问题不做 //qmlRegisterType<mainwindow>("io.qt.mainwindow", 1, 0, "Mwindow"); ui->quickWidget->setSource(source); //添加一项 QQuickItem *item=ui->quickWidget->rootObject(); QVariant returnVar; QString send_time1=QDateTime::fromString(send_time,"yyyyMMddhhmmss").toString("hh:mm"); QVariant arg1 = send_time1; QVariant arg2; QVariant arg3 =send_text; QVariant arg4 =true; QVariant arg5 =false; QVariant arg6="no_reedit"; QVariant arg7=-1; if(send_time1==lastSend_time) { arg2= true; } else { arg2=false; lastSend_time=send_time1; } QMetaObject::invokeMethod(item, "add_message", Q_RETURN_ARG(QVariant, returnVar),Q_ARG(QVariant, arg1),Q_ARG(QVariant, arg2), Q_ARG(QVariant, arg3),Q_ARG(QVariant, arg4),Q_ARG(QVariant, arg5), Q_ARG(QVariant, arg6),Q_ARG(QVariant, arg7)); //cpp中的函数 void mainwindow::listview_item_clicked(const int index, const int id, const QString sendtype, const QString selectedtext,const QString itemtext) { qml_id=id; qml_index=index; qml_sendtype=sendtype; qml_selected_text=selectedtext; qml_item_text=itemtext; //qDebug()<<qml_selected_text; //qDebug()<<qml_item_text; ui->quickWidget->customContextMenuRequested(QPoint(0,0)); } 对qml的值赋给私有变量后就可以实现复制以及定向撤销功能了 //撤销一项 QQuickItem *item=ui->quickWidget->rootObject(); QVariant returnVar; QVariant arg1 = qml_item_index; QMetaObject::invokeMethod(item, "re_edit_item", Q_RETURN_ARG(QVariant, returnVar),Q_ARG(QVariant, arg1)); label_who *label_w1 = (label_who *)(ui->label_2->userData(Qt::UserRole)); //QString send_type=label_w1->send_type; QString send_who=label_w1->send_who; //复制选中的文字;qml文件中实现了选中以后按ctrl+c可以直接复制 void mainwindow::copy_content() { QClipboard *clipboard=QApplication::clipboard(); clipboard->setText(qml_selected_text,QClipboard::Clipboard); } void mainwindow::load_more_for_chatwidget() { if(last_query_number<5){ //只可加载5次 QQuickItem *item=ui->quickWidget->rootObject(); QString current_to_usr_name=ui->listWidget->currentItem()->data(Qt::UserRole+1).toString(); QString item_type=ui->listWidget->currentItem()->data(Qt::UserRole).toString(); QString item_mail=ui->listWidget->currentItem()->data(Qt::UserRole+2).toString(); //再取十条数据 QSqlQuery sql_query; QString select_his_content; if(item_type=="user") { int last_number=last_query_number*10; //limit 必须放在最后... select_his_content="select send_time,send_text from his_tousr " "where tousrmail=:mail " "order by send_time desc " "limit 10 offset :last_number"; sql_query.prepare(select_his_content); sql_query.bindValue(":mail",item_mail); sql_query.bindValue(":last_number",last_number); } else { if(item_type=="group") { int last_number=last_query_number*10; select_his_content="select send_time,send_text from his_group " "where usrgroupname=:groupname " "order by send_time desc " "limit 10 offset :last_number"; sql_query.prepare(select_his_content); sql_query.bindValue(":groupname",current_to_usr_name); sql_query.bindValue(":last_number",last_number); } } if(sql_query.exec()) { while(sql_query.next()) { QString send_time=sql_query.value(0).toString(); QString his_content=sql_query.value(1).toString(); //时间显示控件的格式转换,今天昨天及月日 QString yestoday_date=QDateTime::currentDateTime().addDays(-1).toString("yyyyMMdd"); QString today_date=QDateTime::currentDateTime().toString("yyyyMMdd"); if(send_time.left(8)==today_date) { send_time=(send_time.mid(8,2)+":"+send_time.mid(10,2)); } else { if(send_time.left(8)==yestoday_date) { send_time="昨天 "+send_time.mid(8,2)+":"+send_time.mid(10,2); } else { if(send_time.left(4)==today_date.left(4)) { QDateTime send_time1=QDateTime::fromString(send_time,"yyyyMMddhhmmss"); send_time=send_time1.toString("M月dd日 hh:mm"); } else { QDateTime send_time1=QDateTime::fromString(send_time,"yyyyMMddhhmmss"); send_time=send_time1.toString("yyyy年M月dd日 hh:mm"); } } } QVariant returnVar; QVariant arg1 = send_time; QVariant arg2; QVariant arg3 =his_content; QVariant arg4 =true; QVariant arg5 =false; QVariant arg6="no_reedit"; QVariant arg7=-1; if(send_time==lastSend_time) { arg2= true; } else { arg2=false; lastSend_time=send_time; } QMetaObject::invokeMethod(item, "add_more_message", Q_RETURN_ARG(QVariant, returnVar),Q_ARG(QVariant, arg1),Q_ARG(QVariant, arg2), Q_ARG(QVariant, arg3),Q_ARG(QVariant, arg4),Q_ARG(QVariant, arg5), Q_ARG(QVariant, arg6),Q_ARG(QVariant, arg7)); ui->quickWidget->repaint(); } last_query_number++; } else{ qDebug()<<sql_query.lastError(); } } else { qDebug()<<"nidaye"; QQuickItem *item=ui->quickWidget->rootObject(); QMetaObject::invokeMethod(item,"show_tip"); } } //记录下吧,