/****************************************************************** Copyright © Deng Zhimao Co., Ltd. 1990-2030. All rights reserved. * @projectName tcpclient * @brief TcpClient.qml * @author Deng Zhimao * @email 1252699831@qq.com * @date 2020-06-31 *******************************************************************/ import QtQuick 2.9 import QtQuick.Window 2.2 import mytcpclient 1.0 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.0 import QtQuick.Controls.Styles 1.4 import QtQuick 2.12 import QtQuick.VirtualKeyboard 2.2 import "../helpbutton" Item { visible: false id: window property string netWorkInfo: "" property string connectSate : "请先与服务端连接" HelpMessages { anchors.fill: parent z: 105 appIcon: WINStyle ? "" : "qrc:/desktop/androidstyleicons/tcpclient.png" appName: "Tcp客户端" appVersion: "Version 1.0.0" subtoolText: "1.此软件为tcp客户端,点击聊天中的人物头像可获取本机的ip信息,可断开服务端的连接,清空聊天记录等。 2.输入服务器的ip地址与监听的端口,点击连接即可连接服务端,然后就可以互相发信息聊天!" versionText: "1.【Version 1.0.0 2020-10-06】。\n初始版本" } onVisibleChanged: { formState.state == 'right' ? formState.state = '' : formState.state = 'right' } Component.onCompleted: { mainListview.model.insert(mainListview.model.count, {"detail":"您好!我是TCP客户端小可爱,请输入服务端的IP与端口,再点击连接,即可连接到服务端,点击我头像可查看本地IP信息", "messageBg":"qrc:/tcpclient/images/rightMessagebg.png", "fatherMirroring":false,"childrenMirroring":false, "headPhotoImage":"qrc:/tcpclient/images/gril.jpg", "messBackground":"#b8fa99"}) mainListview.currentIndex = mainListview.count - 1 netWorkInfo = tcpclient.getLocalIpAddress() window.x = parent.width } Item { id: formState states: State { name: "right" PropertyChanges { target: window x: 0 } } transitions: Transition { NumberAnimation { property: "x" easing.type: Easing.InOutQuart duration: 500 } } } MyTcpclient{ id: tcpclient onRecMessageChanged: { // listmodel.append({"detail":tcpclient.recMessage}) mainListview.model.insert(mainListview.model.count,{"detail":tcpclient.recMessage, "messageBg":"qrc:/tcpclient/images/leftMessagebg.png", "fatherMirroring":true,"childrenMirroring":true, "headPhotoImage":"qrc:/tcpclient/images/boy.jpg", "messBackground":"#e3e3f8"}) mainListview.currentIndex = mainListview.count - 1 } onNewConnetChanged:{ connectSate = "断开连接" mainListview.model.insert(mainListview.model.count,{"detail":tcpclient.newConnet, "messageBg":"qrc:/tcpclient/images/rightMessagebg.png", "fatherMirroring":false,"childrenMirroring":false, "headPhotoImage":"qrc:/tcpclient/images/gril.jpg", "messBackground":"#b8fa99"}) mainListview.currentIndex = mainListview.count - 1 } } ListView{ add: Transition { NumberAnimation { properties: "x,y"; from: window.height; duration: 200 } } id: mainListview anchors.top: parent.top anchors.topMargin: 30 anchors.bottom: bottomrect.top anchors.bottomMargin: 10 anchors.left: parent.left anchors.right:parent.right highlightFollowsCurrentItem: true spacing: 30 MouseArea{ width: parent.width - 120 height: parent.height anchors.centerIn: parent onClicked: textfield.focus = false } delegate: Component{ Rectangle{ id: message LayoutMirroring.enabled: fatherMirroring LayoutMirroring.childrenInherit: childrenMirroring height: label1.lineCount * 12 + 35 implicitWidth: fitWidth(label1.text) > window.width * 0.2 ? Math.min(fitWidth(label1.text), window.width * 0.2) + 60 : label1.implicitWidth + 80 color:"transparent" anchors.right: parent.right anchors.rightMargin: 0 Image { anchors.right: parent.right width: 40 height: 40 id: headPhoto source: headPhotoImage MouseArea { anchors.fill: parent onClicked: { onClicked: container.state == 'right' ? container.state = '' : container.state = 'right' } } } Rectangle{ id: myMessbg width: parent.width - 60 anchors.top: parent.top anchors.left: parent.left anchors.bottom: parent.bottom color: messBackground radius: 5 Item{ anchors.left: myMessbg.left anchors.leftMargin: 10 anchors.right: myMessbg.right anchors.rightMargin: 10 anchors.verticalCenter: parent.verticalCenter Text{ id: label1 anchors.fill: parent verticalAlignment: Text.AlignVCenter wrapMode: fitWidth(label1.text) > window.width * 0.2 ? Text.WrapAnywhere:Text.NoWrap text: detail font.pixelSize: 12 } } } BorderImage{ id: mebg source: messageBg anchors.left: myMessbg.right anchors.leftMargin: 0 width: 5 height: 10 anchors.verticalCenter: myMessbg.verticalCenter smooth: true } } } model:ListModel{ id:listmodel // ListElement{ // detail:"请先连接服务器" // } } } function fitWidth(text){ return fontMetrics.advanceWidth(text) } function qmlsendMessage(){ if(textfield.text != ""){ //listmodel.append({"detail":textfield.text}) mainListview.model.insert(mainListview.model.count,{"detail":textfield.text, "messageBg":"qrc:/tcpclient/images/rightMessagebg.png", "fatherMirroring":false,"childrenMirroring":false, "headPhotoImage":"qrc:/tcpclient/images/gril.jpg", "messBackground":"#b8fa99"}) mainListview.currentIndex = mainListview.count - 1 tcpclient.sendMessage(textfield.text) } } FontMetrics { id: fontMetrics //font.family: "Arial" } Rectangle{ z: 55 height: 40 anchors.bottom: pannelbg.top //anchors.bottomMargin: bottomDistance id: bottomrect Row{ Rectangle { height: bottomrect.height width: window.width * 0.4 color: "transparent" Text { id: ipText anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter text: qsTr("IP地址:") font.bold: true font.pixelSize: 13 color: "white" } TextField{ id: ipTextfield placeholderText: "ip" height: bottomrect.height anchors.verticalCenter: parent.verticalCenter width: window.width * 0.15 anchors.left: ipText.right font.pixelSize: 13 color: "white" onFocusChanged: { if(inputPanel.state == 'visible' ) container.state = '' } background: Rectangle{ color: "transparent" Rectangle { anchors.bottom: parent.bottom width: parent.width color: ipTextfield.focus ? "#27d7f0" : "gray" height: ipTextfield.focus ? 2 : 1 } } } Text { id: port anchors.left: ipTextfield.right anchors.leftMargin: 5 anchors.verticalCenter: parent.verticalCenter text: qsTr("端口:") font.bold: true font.pixelSize: 13 color: "white" } TextField{ id: portTextfield font.pixelSize: 13 placeholderText: "port" anchors.left: port.right height: bottomrect.height width: window.width * 0.05 color: "white" anchors.verticalCenter: parent.verticalCenter onFocusChanged: { if(inputPanel.state == 'visible' ) container.state = '' } background: Rectangle{ color: "transparent" Rectangle { anchors.bottom: parent.bottom width: parent.width color: portTextfield.focus ? "#27d7f0" : "gray" height: portTextfield.focus ? 2 : 1 } } } Button{ anchors.left: portTextfield.right anchors.leftMargin: 5 text:"连接" height: bottomrect.height width: window.width * 0.08 font.pixelSize: 13 onClicked: { tcpclient.buttonConnectClicked(ipTextfield.text,portTextfield.text) } } } TextField{ id: textfield placeholderText: "输入要发消息内容" height: bottomrect.height width: window.width * 0.4 Keys.enabled: true font.pixelSize: 13 color: "white" Keys.onReturnPressed : qmlsendMessage() onFocusChanged: { if(inputPanel.state == 'visible' ) container.state = '' } background: Rectangle{ color: "transparent" Rectangle { anchors.bottom: parent.bottom width: parent.width color: textfield.focus ? "#27d7f0" : "gray" height: textfield.focus ? 2 : 1 } } } Rectangle{ height: bottomrect.height width: window.width * 0.2 color: "#55111111" Button{ anchors.fill: parent text:"发送(或者按回车键)" font.pixelSize: 13 onClicked: { qmlsendMessage() } } } } } Rectangle{ z: 88 id: pannelbg width: parent.width anchors.bottom: inputPanel.top height: inputPanel.state == "visible" ? 28 * window.height / 480 : 0 color: "black" } InputPanel { id: inputPanel z: 88 //x: -11 y: window.height visible: parent.visible width: window.width states: State { name: "visible" when: inputPanel.active PropertyChanges { target: inputPanel y: window.height - inputPanel.height } } transitions: Transition { from: "" to: "visible" reversible: true ParallelAnimation { NumberAnimation { properties: "y" duration: 250 easing.type: Easing.InOutQuad } } } } Item { id: container states: State { name: "right" PropertyChanges { target: grilInfo x: parent.width * (smallScreen ? 0.50 : 0.65) } } transitions: Transition { NumberAnimation { property: "x" easing.type: Easing.InOutQuart duration: 1000 } } } Item { id: grilInfo z: 40 width: parent.width * (smallScreen ? 0.50 : 0.35) height: parent.height x: parent.width Flickable { id: myflickable anchors.fill: parent contentWidth: parent.width contentHeight: parent.height + (smallScreen ? 208 : 20) Rectangle{ anchors.fill: parent color: "#cc424242" MouseArea { anchors.fill: parent onClicked: { onClicked: container.state == 'right' ? container.state = '' : container.state = 'right' } } } Image { id: boyID source: "qrc:/tcpclient/images/gril.jpg" width: 50 height: 50 anchors.left: parent.left anchors.leftMargin: 20 anchors.top: parent.top anchors.topMargin: 30 } Text { id: juese anchors.left: boyID.right anchors.leftMargin: 20 anchors.top: boyID.top text: qsTr("角色:TCP客户端") color: "white" font.bold: true font.pixelSize: 15 } Text { id: idName text: qsTr("I D:小可爱") lineHeightMode: Text.FixedHeight //设置行间距 以像素的方式设置 lineHeight: 18 //行间距比例 最大 1 anchors.left: juese.left anchors.top: juese.bottom anchors.topMargin: 5 color: "#99eeeeee" font.bold: true font.pixelSize: 14 } Text { anchors.top: boyID.bottom anchors.topMargin: 30 anchors.horizontalCenter: parent.horizontalCenter id: networkMess text: netWorkInfo color: "#28dcf7" font.bold: true font.pixelSize: 13 } Button{ id: refreshBtn anchors.top: networkMess.bottom anchors.horizontalCenter: parent.horizontalCenter width: 40 height: 40 background: Rectangle{ color: "transparent" Image { //anchors.fill: parent anchors.centerIn: parent id: refresh source: "qrc:/tcpclient/images/refresh.png" } } onClicked: { netWorkInfo = "正在读取本地网卡信息,请稍候..." refreshAnima.running = true } } RotationAnimator { id: refreshAnima target: refreshBtn from: 0 to: 360 duration: 1000 //loops: Animation.Infinite running: false onRunningChanged: { if (running === false) { from = refreshBtn.rotation; to = from+360; } } onStopped: { netWorkInfo = tcpclient.getLocalIpAddress() } } Button{ id: clearMessage anchors.top: refreshBtn.bottom //anchors.topMargin: -20 anchors.horizontalCenter: parent.horizontalCenter width: 120 height: 35 background: Rectangle{ color: "transparent" radius: 20 border.color: "#28dcf7" border.width: 1 Text { anchors.centerIn: parent id: clearText text: qsTr("清空所有聊天记录") font.pixelSize: 13 color: clearMessage.pressed ? "white":"#28dcf7" } } onClicked: { if(mainListview.count != 0) mainListview.model.clear() mainListview.model.insert(mainListview.model.count,{"detail":"已经清空!", "messageBg":"qrc:/tcpclient/images/rightMessagebg.png", "fatherMirroring":false,"childrenMirroring":false, "headPhotoImage":"qrc:/tcpclient/images/gril.jpg", "messBackground":"#b8fa99"}) mainListview.currentIndex = mainListview.count - 1 } } Button{ id: disConetFromClient anchors.top: clearMessage.bottom anchors.topMargin: 10 anchors.horizontalCenter: parent.horizontalCenter width: 120 height: 35 background: Rectangle{ color: "transparent" radius: 20 border.color: "#28dcf7" border.width: 1 Text { anchors.centerIn: parent id: disConetText text: connectSate color: disConetFromClient.pressed ? "white":"#28dcf7" font.pixelSize: 13 } } onClicked: { tcpclient.disConnect() connectSate = "已断开连接" } } } } }