Linux系统开发

2023-11-05

一、实验目的
设计一款携带多种功能的聊天软件,不仅可以聊天,也能修改字体,计时,绘画等等。
二、实验内容:
1)ui设计(满分15分)
2)画图、timer、多线程(满分20分)
3)数据库操作(满分15分)
4)TCP网络通信(满分40分) (客户端15分,多线程服务器25分)

三、实验环境

Qt Creator 4.2.1 (Community)

四、实验过程与运行结果
1)ui设计
在这里插入图片描述
图表 1聊天界面

头像是在网络上找的,其余图标都是自己绘制的,但由于设计时间过早,在后面完成代码的时候发现没有信息的数据库,所以这里的了解成员要改为查找地址。
在这里插入图片描述
图表 2设计界面2
这是设计的第二个界面,但是本来想要管理员链接服务端,但是因为项目的问题一直链接不上,排查问题找了很久都没有找到问题,所以这里设计的按钮其实是无法跳转的,所以就改为第一次的设计。
在这里插入图片描述
图表 3绘画界面
在这里插入图片描述
图表 4客户端界面
在这里插入图片描述
图表 5服务端界面

2)画图、timer、多线程
在这里插入图片描述
图表 6多线程聊天
可进行多人聊天,只要打开窗口就能够聊天,但如果其他人要接收的话,也需要打开聊天框,不然就不能够接收到信息。
在这里插入图片描述
图表 7保存聊天记录
这里为了合理化也设计了字体样式的更改,保存,清空等等,但是颜色字号因为不太理解所以没有做成功,但加粗等成功了。
在这里插入图片描述
图表 8保存的聊天记录
在这里插入图片描述
图表 9修改字体样式
在这里插入图片描述
图表 10警告
为了不出现重复聊天框的BUG,所以要设置一个警告。
在这里插入图片描述

图表 11绘图界面
这里只绘制了一个圈和字体,但也可以实现其他的绘画,比如画直线等等,但需要在代码中加入,这里没有加是因为我觉得这样设计会比较好看。
在这里插入图片描述

图表 12绘画界面弹出
只要点击来画画吧,就会弹出绘画的这个窗口,这里本来想设计成后面的那些窗口都消失,但发现这样不太明显,就将那条代码删除了。
在这里插入图片描述

图表 13计时器
点击计时器按钮,就会跳转到计时器的这个页面来,点击开始就能够开始计时,停止就停止计时,重置就是重新开始。
在这里插入图片描述

图表 14点击重置后
点击重置后,时间就归零了。
3)数据库操作
在这里插入图片描述

图表 15数据库登录
这里是老师上课讲解的内容,这里进行了一个结合,只要点击右下方的按钮,就能够弹出这个页面,也就是“小蜜蜂数据”,接着就能够链接数据库查询信息了。
在这里插入图片描述

图表 16查询信息页面
因为没有数据库,所以这里用的是老师之前教课时所使用的,自己也尝试建立数据库,发现了很多问题,诸如数据的问题,要创建ID类但是一直无法设置好,导致程序出现故障等等。
在这里插入图片描述

图表 17重新建立数据库界面
因为原本数据库不太适合我的聊天软件,于是进行了更改,这样就能够查询好友的信息,比较匹配我的聊天软件。
4)TCP网络通信
在这里插入图片描述

图表 18同时打开服务端和客户端
能够运行服务端和客户端,界面上的LOGO是我设计的小蜜蜂。
在这里插入图片描述

图表 19多线程链接
两个客户端能够和服务端链接并且发送消息。
在这里插入图片描述

图表 20单线程链接
以下是主代码展示:【代码不全】

1)Widegt.cpp

#include "widget.h"
#include "ui_widget.h"
#include"draw.h"
#include "mytime.h"
#include "mydb.h"
#include <QString>
#include <QDataStream>
#include <QMessageBox>
#include <QDateTime>
#include <QDebug>
#include <QFont>
#include <QColor>
#include <QColorDialog>
#include <QFileDialog>
#include <QTextStream>
#include <QFontDialog>
#include <QPushButton>

Widget::Widget(QWidget *parent ,QString name) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    myname=name;

    this->ppage2=new draw;//实例化绘画页面S
    connect(ui->drawBtn,&QPushButton::clicked,[=](){
        //this->hide();
        this->ppage2->show();//显示
    });

    this->ppage3=new mytime;
    connect(ui->timerBtn,&QPushButton::clicked,[=](){
        this->ppage3->show();
    });

    this->ppage4=new mydb;
    connect(ui->dataBtn,&QPushButton::clicked,[=](){
        this->ppage4->show();
    });



    this->port=0032;
    this->udpSocket=new QUdpSocket(this);

    udpSocket->bind(this->port,QUdpSocket::ShareAddress |QUdpSocket::ReuseAddressHint);

    connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::ReceiveMessage);
    connect(ui->sendBtn,&QPushButton::clicked,[=](){
        sndMsg(Msg);
    });
}

void Widget::sndMsg(Widget::Msgtype type)
{
    QByteArray array;
    QDataStream stream(&array,QIODevice::WriteOnly);
    stream<<type<<this->getName();

    switch(type){
    case Msg:
        if(ui->msgTxtEdit->toPlainText()=="")
        {
            QMessageBox::warning(this,"警告","发送的内容不能为空!");
            return;
        }
        stream<<this->getMsg();
        break;
    case UserEnter:
        break;
    case UserLeft:
        break;
    }
    udpSocket->writeDatagram(array.data(),array.size(),QHostAddress::Broadcast,this->port);
}

QString Widget::getName()
{
    return this->myname;
}

QString Widget::getMsg()
{
    QString msg=ui->msgTxtEdit->toHtml();
    ui->msgTxtEdit->clear();
    ui->msgTxtEdit->setFocus();
    return msg;
}



void Widget::ReceiveMessage()
{
    qint64 size=udpSocket->pendingDatagramSize();
    int mysize=static_cast<int>(size);
    QByteArray *array=new QByteArray(mysize,0);
    udpSocket->readDatagram((*array).data(),size);
    QDataStream stream(array,QIODevice::ReadOnly);
    int mytype;
    QString name,msg;//聊天内容 用户名
    QString time=QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    stream>>mytype;
    switch(mytype){
    case Msg:
        stream>>name>>msg;
        ui->msgBrowser->setTextColor(QColor(Qt::blue));
        ui->msgBrowser->setCurrentFont(QFont("Times New Roman",10));
        ui->msgBrowser->append(("["+name+"]"+time));
        ui->msgBrowser->append(msg);
        break;
    case UserEnter:
        stream>>name;
//        userEnter(name);
        break;
    case UserLeft:
        stream>>name;
//        userLeft(name,time);
        break;
    }
    //字体改变
    connect(ui->fontCbx,&QFontComboBox::currentFontChanged,[=](const QFont &font){
        ui->msgTxtEdit->setFontFamily(font.toString());
        ui->msgTxtEdit->setFocus();
    });
    //字体大小
    void (QComboBox:: *sizebtn)(const QString &text)=&QComboBox::currentTextChanged;
    connect(ui->sizeCbx,sizebtn,[=](const QString &text){
       ui->msgTxtEdit->setFontPointSize(text.toDouble());
       ui->msgTxtEdit->setFocus();
    });
    //加粗
    connect(ui->boldTBtn,&QToolButton::clicked,this,[=](bool checked){
        if(checked)
        {
            ui->msgTxtEdit->setFontWeight(QFont::Bold);
        }
        else{
            ui->msgTxtEdit->setFontWeight(QFont::Normal);
        }
    });
    //倾斜
    connect(ui->italicTbtn,&QToolButton::clicked,this,[=](bool checked){
        ui->msgTxtEdit->setFontItalic(checked);
        ui->msgTxtEdit->setFocus();
    });
    //下划线
    connect(ui->underlineTBtn,&QToolButton::clicked,this,[=](bool checked){
        ui->msgTxtEdit->setFontUnderline(checked);
        ui->msgTxtEdit->setFocus();
    });
    //清除
    connect(ui->clearTBtn,&QToolButton::clicked,[=](){
        ui->msgBrowser->clear();
    });
    //颜色
    connect(ui->colorTBtn,&QToolButton::clicked,this,[=](){
        QColor color=QColorDialog::getColor(color,this);
        ui->msgBrowser->clear();
    });
    //保存
    connect(ui->saveTBtn,&QToolButton::clicked,[=](){
        if(ui->msgBrowser->document()->isEmpty())
        {
            QMessageBox::warning(this,"警告","保存内容不能为空!");
            return;
        }
        else{
            QString filename=QFileDialog::getSaveFileName(this,"保存聊天记录","聊天记录","(*.txt");
            if(!filename.isEmpty())
            {
                QFile file(filename);
                file.open(QIODevice::WriteOnly |QFile::Text);
                QTextStream stream(&file);
                stream<<ui->msgBrowser->toPlainText();
                file.close();
            }
        }
    });
}

void Widget::closeEvent(QCloseEvent *)
{
    emit this->closeWidget();
}

Widget::~Widget()
{
    delete ui;
}2)Wedget.h

#ifndef WIDGET_H
#define WIDGET_H
#include "draw.h"
#include <QWidget>
#include <QUdpSocket>
#include "mytime.h"
#include "mydb.h"


namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    enum Msgtype{Msg,UserEnter,UserLeft};
    explicit Widget(QWidget *parent, QString name);

    void sndMsg(Msgtype type);
    QString getName();
    QString getMsg();
    QString getIcon();
    void userEnter(QString username);
    void userLeft(QString username,QString time);
    void ReceiveMessage();

    ~Widget();
    draw *ppage2=NULL;//用来保存绘画界面的实例化对象地址
    mytime *ppage3=NULL;//计时器
    mydb *ppage4=NULL;//数据库


signals:
    void closeWidget();
    void showmain();

private:
    Ui::Widget *ui;
    quint16 port;
    QString myname;
    QUdpSocket *udpSocket;
public:
    void closeEvent(QCloseEvent *);

};

#endif // WIDGET_H3)denglu.cpp

#include "denglu.h"
#include "ui_denglu.h"
#include <QIcon>
#include <QToolButton>
#include <QList>
#include <QString>
#include <widget.h>
#include <QMessageBox>
denglu::denglu(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::denglu)
{
    ui->setupUi(this);
    //图标
    this->setWindowIcon(QIcon(":/image/bee.PNG"));
    //名称
    this->setWindowTitle("小蜜蜂聊天");
    QList<QString> namelist;
    namelist<<"喝饮料的小熊猫"<<"今天很开心"<<"保佑及格!"<<"天选锦鲤在哪里"<<"好好学习天天向上";
    QStringList iconNameList;
    iconNameList<<"1"<<"2"<<"3"<<"4"<<"5";
    QVector<QToolButton *> vector;
    for(int i=0;i<5;i++)
    {
        QToolButton *btn=new QToolButton(this);
        //头像
        btn->setIcon(QPixmap(QString(":/image/%1.png").arg(iconNameList[i])));
        btn->setIconSize(QPixmap((QString(":/image/%1.png").arg(iconNameList[i]))).size());
        btn->setText(QString("%1").arg(namelist[i]));
        btn->setAutoRaise(true);
        btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
        ui->vlayout_2->addWidget(btn);
        vector.push_back(btn);
        IsShow.push_back(false);
    }
    for(int i=0;i<5;i++)
    {
        connect(vector[i],&QToolButton::clicked,[=](){
            if(IsShow[i])
            {
                QMessageBox::warning(this,"警告","已有相关聊天框,请勿重复点击!");
                return;
            }
            IsShow[i]=true;
            Widget *widget=new Widget(nullptr,vector[i]->text());
            widget->setWindowIcon(vector[i]->icon());
            widget->setWindowTitle(vector[i]->text());
            widget->show();

            connect(widget,&Widget::closeWidget,this,[=](){
                IsShow[i]=false;
            });
        });
    }
}

denglu::~denglu()
{
    delete ui;
}4)denglu.h

#ifndef DENGLU_H
#define DENGLU_H

#include <QDialog>

namespace Ui {
class denglu;
}

class denglu : public QDialog
{
    Q_OBJECT

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

private:
    Ui::denglu *ui;
    QVector<bool> IsShow;
};

#endif // DENGLU_H5)draw.cpp

#include "draw.h"
#include "ui_draw.h"
#include <QPainter>
#include"qpainter.h"
draw::draw(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::draw)
{
    ui->setupUi(this);
    this->setWindowIcon(QIcon(":/image/bee.PNG"));
    this->setWindowTitle("小蜜蜂绘画");
}

draw::~draw()
{
    delete ui;
}

void draw::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

       QPainter painter(this);
       // 设置画笔颜色
       painter.setPen(QColor(0, 160, 230));

       // 设置字体:微软雅黑、点大小50、斜体
       QFont font;
       font.setFamily("Microsoft YaHei");
       font.setPointSize(50);
       font.setItalic(true);
       painter.setFont(font);

       // 绘制文本
       painter.drawText(rect(), Qt::AlignCenter, "小蜜蜂");

       Q_UNUSED(event);
         painter.begin(this);
         QRectF rectangle(150.0, 100.0, 280.0, 240.0);//如果是一个正方形那就是一个圆
         painter.drawEllipse(rectangle);
         painter.end();



}6)mytime.cpp

#include "mytime.h"
#include "ui_mytime.h"
#include <QTimer>
#include <QTime>
#include <QDebug>

mytime::mytime(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::mytime)
{
    ui->setupUi(this);
    this->setWindowIcon(QIcon(":/image/bee.PNG"));
    this->setWindowTitle("小蜜蜂计时器");
    time.setHMS(0,0,0,0);//设置初始值
    timer = new QTimer(this);//创建一个定时器
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
}

mytime::~mytime()
{
    delete ui;
}

void mytime::update()
{
    static quint32 time_out=0;
            time_out++;
            time=time.addSecs(1);
            ui->label->setText(time.toString("hh:mm:ss"));

}

void mytime::on_startBtn_clicked()
{
    timer->start(1000);
}

void mytime::on_stopBtn_clicked()
{
   timer->stop();
}

void mytime::on_reBtn_clicked()
{
    timer->stop();
    time.setHMS(0,0,0,0);
    ui->label->setText(time.toString("hh:mm:ss"));
}7)mserver.cpp

#include "mserver.h"
#include "ui_mserver.h"

mServer::mServer(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::mServer)
{
    ui->setupUi(this);
    this->setWindowIcon(QIcon(":/image/bee.PNG"));
    this->setWindowTitle("小蜜蜂服务端");
    list_sock.clear();
    mserver=new QTcpServer();
    connect(mserver,SIGNAL(newConnection()),this,SLOT(acceptListen()));

    ui->tabClient->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    mtype=msize=0;
    mdata.clear();
}

mServer::~mServer()
{
    delete ui;
}

void mServer::sendData()
{
    int rows=ui->tabClient->rowCount();
    if(rows<1) return;
    int row=ui->tabClient->currentIndex().row();
    list_sock[row]->write(mdata);
    mdata.clear();
}

void mServer::processData(int id)
{

}

void mServer::acceptListen()
{
    QTcpSocket *sock=mserver->nextPendingConnection();
    list_sock.append(sock);
    connect(sock,SIGNAL(readyRead()),this,SLOT(recvData()));

    int rows=ui->tabClient->rowCount();
    ui->tabClient->insertRow(rows);
    ui->tabClient->setItem(rows,0, new QTableWidgetItem(sock->peerAddress().toString()));
    ui->tabClient->setItem(rows,1, new QTableWidgetItem(QString::number(sock->peerPort())));
    QString str=QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    ui->tabClient->setItem(rows,2, new QTableWidgetItem(str));
}

void mServer::recvData()
{
    QTcpSocket *sock = (QTcpSocket*)sender();
    for(int i=0;i<list_sock.length();i++)
    {
        if(sock == list_sock[i])
        {
            QString str=sock->peerAddress().toString()+"---"+QString::number(sock->peerPort())+":";
            QString str1 = QString::fromLocal8Bit(sock->readAll());
            ui->textEdit->append(str);
            ui->textEdit->append(str1);
        }
    }
}

void mServer::on_btn_listen_clicked()
{
    if(!mserver->listen(QHostAddress::Any,22233))
    {
        qDebug()<<mserver->errorString();//>>log.txt
        return;
    }
}

void mServer::on_btn_discon_clicked()
{
    mserver->close();
    for(int i=0;i<list_sock.length();i++)
    {
        list_sock[i]->abort();  //disconnect
    }
    list_sock.clear();

    exit(0);
}

void mServer::on_btn_sendMsg_clicked()
{
    QDataStream out(&mdata,QIODevice::WriteOnly); //memcpy
    out.setVersion(QDataStream::Qt_5_8);
    mtype=101; //101 102 103   201 202
    QString str=ui->text_send->text();
    QByteArray ba=str.toLocal8Bit();
    msize=ba.length();
    out<<mtype; out<<msize;
    mdata.append(ba);
    ba.clear();

    sendData();
}

void mServer::on_btn_sendFile_clicked()
{
    QString fpath=QFileDialog::getOpenFileName();
    if(fpath.isEmpty()) return;
    mtype= (fpath.endsWith("jpg"))?103:102;

    QFile mfile(fpath);
    QByteArray data;
    if(!mfile.isOpen())
    { mfile.open(QIODevice::ReadOnly);
        data = mfile.readAll();
    }
    mfile.close();
    msize=data.length();

    mdata.clear();
    QDataStream out(&mdata,QIODevice::WriteOnly); //memcpy
    out.setVersion(QDataStream::Qt_5_8);
    out<<mtype; out<<msize;
    mdata.append(data);
    qDebug()<<mtype<<msize;

    sendData();
}8)mclient.cpp

#include "mclient.h"
#include "ui_mclient.h"

mclient::mclient(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::mclient)
{
    ui->setupUi(this);
    this->setWindowIcon(QIcon(":/image/bee.PNG"));
    this->setWindowTitle("小蜜蜂客户端");
    sock=new QTcpSocket();
    connect(sock,SIGNAL(readyRead()),this,SLOT(recvData()));
    size=recvsize=totalsize=mtype=0;
    send_data.clear();

    devid=locid=0;
    list_random.clear();
}

mclient::~mclient()
{
    delete ui;
}

void mclient::processData()
{
    if(mtype == 101)
    {
        ui->text_recv->clear();
        ui->text_recv->append(QString::fromLocal8Bit(mdata));
    }
    if(mtype == 102)
    {
        ui->text_recv->clear();
        ui->text_recv->append(QString::fromLocal8Bit(mdata));
    }
    if(mtype == 103)
    {
        QBuffer buffer(&mdata);
        buffer.open( QIODevice::ReadOnly);

        QImageReader reader(&buffer, "jpg");
        QImage image = reader.read();
        QImage img=image.scaled(ui->labImg->rect().width(),ui->labImg->rect().height(),Qt::IgnoreAspectRatio);
        ui->labImg->clear();
        ui->labImg->setPixmap(QPixmap::fromImage(img));
    }

}

void mclient::recvData()
{
    if(sock->bytesAvailable()<8) return;  //type  size

    if(totalsize < 1)
    {
        QDataStream in(sock);
        in.setVersion(QDataStream::Qt_5_8);
        in>>mtype; in>>totalsize; mdata.clear(); //cont  25k
        qDebug()<<mtype;
    }
    if(recvsize<totalsize)
    {
        quint32 len=(quint32)sock->bytesAvailable();
        recvsize += len;
        mdata.append(sock->readAll());
        if(recvsize == totalsize)
        {
            processData();
        }
    }
}

void mclient::on_btn_con_clicked()
{
    sock->connectToHost(ui->textIP->text(),(quint16)ui->textPort->text().toUInt());
}

void mclient::on_btn_send_clicked()
{
    QDataStream out(&send_data,QIODevice::WriteOnly); //memcpy
    out.setVersion(QDataStream::Qt_5_8);
    // mtype=201; //101 102 103   201 202
    QString str=ui->lineEdit->text();
    QByteArray ba=str.toLocal8Bit();
    //    size=ba.length();
    //  out<<mtype; out<<size;
    send_data.clear();
    send_data.append(ba);
    ba.clear();

    sock->write(send_data);
    send_data.clear();
}

void mclient::on_btn_discon_clicked()
{
    sock->abort();
    exit(0);
}

void mclient::on_btn_gendata_clicked()
{
    devid=(quint8)(ui->text_devid->text().toInt());
    locid=(quint8)(ui->text_locid->text().toInt());

    float a=1.0; float b=100.0; mtype=size=0;

    for(int i=0;i<7;i++)
    {
        QTime t= QTime::currentTime();
        qsrand(t.msec()+t.second()*100);
        list_random.append(qrand());
        QThread::msleep(30);
    }

    float v1=(float)((450+list_random[0]%100)*a);
    float v2=(float)((20+list_random[1]%50)*a);
    float v3=(float)((100+list_random[2]%400)*a);
    float v4=(float)((5+list_random[3]%25)*a);
    float v5=(float)((5+list_random[4]%20)*a);
    float v6=(float)((26+list_random[5]%7)*a);
    float v7=(float)((85+list_random[6]%7)/b);

    send_data.clear();
    mtype=222;
    QByteArray ba; ba.clear();
    QDataStream out1(&ba,QIODevice::WriteOnly);
    out1.setVersion(QDataStream::Qt_5_8);
    out1<<devid<<locid<<v1<<v2<<v3<<v4<<v5<<v6<<v7;
    size=(quint32)ba.length();

    QDataStream out(&send_data,QIODevice::WriteOnly);
    out1.setVersion(QDataStream::Qt_5_8);
    out<<mtype<<size;
    send_data.append(ba);

    sock->write(send_data);
//    qDebug()<<mtype<<size<<devid<<locid<<v1<<v2<<v3<<v4<<v5<<v6<<v7;
    send_data.clear();

}

五、实验总结
在本次实践学习中,我运用上课学习到的知识进行了自己的设计制作,会发现当跟着老师的时候会觉得很轻松的事情,自己上手了却变得困难了,比如多线程这一块内容,跟着老师走的时候就会知道下一步应该走向哪里,但是自己打开的时候却经常报错,而且因为地址的问题要找很多的资料,反复去回忆老师所讲过的内容,因为要复制一些程序到源地址中,而这几个程序我印象不深,所以也导致了在这个问题上面浪费太多时间,这也让我决定以后类似于这样的知识点应该记录到笔记中去。
还有就是手动建槽的时候也要注意规范,之前因为想测试某个功能,忘记在头文件中加入槽,等反应过来之后再去添加槽,却发现还是运行不了,代码也找了很多参考,但是都没有能够找出问题,所以这一个内容我全部删除重新再打一次代码,而后就运行成功了,所以我也认识到规范性也是很重要的。
在最初的UI设计中我是参考别人的设计,和同学一起讨论设计出来的,但发现功能太少了,远远不符合要求,所以再翻找以前的学习代码去找该怎么实现我想要的功能,然后再进行设计,所以在最初设计的基础上做了很多变动,比如因为没有数据库,所以和我最先设想的查找好友资料也无法做出来,只能参考原来上课时候的学习代码进行制作,还有原本想要管理员按钮连接服务端进行跳转,却发现服务端需要单独开设一个项目,那如何把项目放在另一个项目下面我也是找了很多资料,但也一直无法实现,这也是我的一个遗憾,就是无法在一个项目中同时做到多个功能,只能在聊天的基础上搭载绘画,计时器,天气数据查询等的功能。
最后就是代码,其实我参考学习了很多资料,包括之前上课所讲的代码,我都有做参考,在这个过程中也重新学到了很多知识,也算是查缺补漏了,刚开始觉得这个作业很难,但后来一步一步一个一个功能慢慢实现之后,就会发现其实还是能够完成的,每次遇到难题我都会去请教舍友或者网上搜索资料,一步一步试错也让我曾经很崩溃,有时候一整天都在完成一个功能,虽然最后结果出来之后不是很惊艳,但是我觉得我已经做到了我的最好,也学习到了很多!

能做出这个软件,也很感谢:
B站up主:性感的大飞侠-【QT实现群聊聊天系统-哔哩哔哩】 https://b23.tv/yrhCLWL
唔国旗u【04_QT_页面切换(两个ui界面)-哔哩哔哩】 https://b23.tv/wEWbfqW

以上指导很有用!

实验结果存在较多BUG,很不完善!欢迎讨论!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux系统开发 的相关文章

  • 删除 QComboBox“下拉”动画

    我正在使用 Qt 4 8 并且想在单击 QComboBox 时摆脱 下拉 动画 我也想稍微移动一下 到目前为止 我一直在考虑重新实现 showPopup 和 hidePopup 但不知道如何使其工作 此外 每次我尝试使用 CSS 进行移动或
  • 通过对 XmlHttpRequest (REST) 的响应在 QML 中显示图像

    我需要从 REST API 调用中获取 jpeg 图像 我使用 XMLHttpRequest 因为请求需要身份验证标头 即我不能只创建一个图像并将源设置为带有 user passwd url 的 URL 我认为我可以通过将 REST 数据设
  • 如何恢复 QSS 属性的默认系统值?

    如果父级之一将其样式表设置为 Qt QSS 会传播给子级color red 它的所有子级都将应用此样式表 如果你明确设置QLabel color red 那么只有 QLabel 子项会受到关注 如果子项设置自己的值 则可以覆盖子项的样式表c
  • Qt 计算和比较密码哈希

    目前正在 Qt 中为测验程序构建面向 Web 的身份验证服务 据我了解 在数据库中存储用户密码时 必须对其进行隐藏 以防落入坏人之手 流行的方法似乎是添加的过程Salt https en wikipedia org wiki Salt cr
  • QTableView 中的虚拟列?

    我开始学习 Qt4 模型 视图编程 我有初学者问题 我有一个简单的应用程序 其中显示 sqlite 表QTableView class Model QtSql QSqlTableModel def init self parent None
  • Qt程序部署到多平台,如何?

    我是 Qt 编程新手 我想开发一个程序 我想在 Windows Linux ubuntu 和 Mac 上运行 听说Qt支持多平台应用程序开发 但我的问题是 在我部署或编译后 任何 Qt 库都需要在 Ubuntu 中运行这个应用程序吗 如果您
  • 如何在 C++ 和 QML 应用程序中使用 qrc?

    我在 Windows7 上用 c qnd Qt Creator QML 编写了 Qt Quick Desktop 应用程序 现在 我必须部署它 并且我需要隐藏 qml 文件和图像 意味着 将它们放入资源等中 我读到有一个很好的方法可以使用
  • 使用 cmake 将两种解决方案合二为一

    我有两个单独的 Visual Studio 2013 解决方案 我想将它们迁移到一个解决方案中 因为第一个解决方案 使用 Qt 充当第二个解决方案的 GUI 最后 我希望有一个结构如下的单一解决方案 Solution All Build P
  • 有没有办法在没有 QApplication::exec() 的情况下使用 Qt?

    有没有一种安全的方法可以在不调用 QApplication exec 的情况下使用 Qt 我有许多不同的对象正在对多个资源执行长期进程 至少其中一个正在与 Web 应用程序服务器进行通信 我正在制作一个 GUI 应用程序 提示用户在正确的时
  • Qt WinRT 应用程序无法访问文件权限被拒绝

    我需要使用 Qt 和 FFMPEG 开发 WinRT 应用程序 我根据指令构建了 WinRT 的 ffmpeghere https github com Microsoft FFmpegInterop我可以将库与我的项目链接起来 现在我需要
  • QTcpSocket 有时不发送数据

    我有两个 QT 应用程序 一个应用程序可以被认为保存了大数据 它每秒向第二个应用程序发送大约 10 KB 的数据块 之前我尝试使用QUdpSocket来传输数据 但由于MTU限制在2 5K左右 并且需要自己分割和重新组合数据 所以我改用QT
  • Qt - 如何粘合两个窗口并将它们移动在一起?

    就像qmmp Qt 音乐播放器ui设计一样 这两个或三个窗口实际上在同一个窗口中 因为只有一个dock图标 并且这些窗口可以一起移动并相互附着 我看了源码 好像有用QDockWidget 但我真的不知道如何获得它的细节 当您手动移动辅助窗口
  • 在 Qt5 中,是否需要 Q_INVOKABLE 来从 QML 调用公共 QObject 函数?

    我刚刚意识到我可以调用暴露于 QML 的对象的几乎任何函数 现在我对 Q INVOKABLE 很好奇 Qt5docs http doc qt io qt 5 qtqml cppintegration exposecppattributes
  • 如何创建用于 QML 的通用对象模型?

    我想知道是否有任何宏或方法如何将 Qt 模型注册为 QObject 的属性 例如 我有AnimalModel http doc qt io qt 5 qtquick modelviewsdata cppmodels html qabstra
  • 更改 Qt OpenGL 窗口示例以使用 OpenGL 3.3

    我正在尝试更改 Qt OpenGL 示例以使用更现代的 opengl 版本 330 似乎合适 所以我做了 在 main cpp 上设置版本和配置文件 设置着色器版本 更改着色器以使用统一 它现在构建没有任何错误 但我只看到一个空白窗口 我错
  • 如何在 QTabWidget Qt 中展开选项卡

    我有一个QTabWidget像这个 但我想展开选项卡以 填充 整个小部件宽度 如下所示 我怎样才能做到这一点 我在用Qt 5 3 2 and Qt 创建者 3 2 1 Update 我尝试使用setExpanding功能 ui gt myT
  • 退出 Qt 程序的正确方法?

    我应该如何退出 Qt 程序 例如在加载数据文件时 发现文件损坏 并且用户需要退出该应用程序或重新启动数据文件 我是不是该 call exit EXIT FAILURE call QApplication quit call QCoreApp
  • 如何使QTableView类的restoreState()和saveState()正常工作?

    首先 我想说 我的问题已经在这里讨论过 并且这里是 https stackoverflow com questions 1163030 qt qtableview and horizontalheader restorestate 但答案并
  • QTimer 一点也不准确?

    运行在 Windows7 64 位机器上 具有非常强大的 CPU 8 核 16 线程 我使用 QTimer 以 50Hz 触发函数调用 但我最终得到了 30Hz 函数调用本身肯定需要不到 10 毫秒才能完成 整个过程发生在一个单独的线程中
  • PyQt5:如何使QThread返回数据到主线程

    I am a PyQt 5 4 1 1初学者 我的Python是3 4 3 这是我尝试遵循的many https mayaposch wordpress com 2011 11 01 how to really truly use qthr

随机推荐

  • LINUX:开发中用得较多的一些操作

    目录文件相关 cd命令用来切换工作目录至dirname 其中dirName表示法可为绝对路径或相对路径 若目录名称省略 则变换至使用者的home directory 也就是刚login时所在的目录 另外 也表示为home directory
  • [记录]centos java mysql链接错误

    项目场景 CentOS 7 3 JDK openjdk version 1 8 0 302 Mysql 5 7 35 问题描述 数据库链接错误 Communications link failure Caused by javax net
  • Google Filament 源码学习(五):Material System (四) - 材质系统 API

    目录 Shader public APIs Introduction Types Math Matrices Frame constants Vertex only Fragment only Handling colors Linear
  • android开发图片分辨率

    一直受到android开发图片分辨率问题困扰 drawable xdpi hdpi mdpi ldpi nodpi 这几个文件夹到底怎么放图片呢 dpi是什么呢 dpi是 dot per inch 的缩写 每英寸像素数 四种密度分类 ldp
  • OpenCV人脸检测及识别(深度学习)

    简介 最近做了一个人脸检测以及识别的程序 很多的文章都有比较详细的叙述 可以自行查找 但是个人觉得大部分文章都太细致了以至于初学者无法快速领会主干 不是否认质量 是侧重点问题 所以结合我遇到了一些问题 现在做个总结 本文主要叙述实现的思路
  • Batch Processing

    在学习HOG SVM实现手写识别算法的过程中 看到对图片库文件夹提取文件名及标签的操作 即生成一个文本文件 按照文件名 标签的格式依次存储 为换行的意思 zaza Ji轻度强迫症 捣饬了半天才写出了个一行的批处理代码 我也是醉了 仅此留个纪
  • 如何实现apex的安装工作?

    1 具体的apex安装步骤 swav luanhaijing gpu02 extract swav feature git clone https github com ptrblck apex git Cloning into apex
  • VSCODE CMAKE C++ 工程调试, C++不以科学计数法输出并控制小数位数

    1 VSCODE调试CMAKE工程配置 1 1 修改CMakeLists txt文件 1 2 程序中 1 3 launch json配置 1 4 开始调试 1 5 注意 2 C 设置输出浮点数且保留位数固定 1 VSCODE调试CMAKE工
  • 通过 rqt_plot 完成ATI F/T 力和力矩传感器六轴数据可视化

    基于该篇博客https blog csdn net qq 34935373 article details 103481401 实现了通过ROS节点的方式启动ATI sensor 完成配置归零和设置软件矢量偏移 并且获取六轴数据 实时的打印
  • Linux:运行存在的可执行文件提示 No such file or directory

    1 前言 限于作者能力水平 本文可能存在谬误 因此而给读者带来的损失 作者不做任何承诺 2 背景 本文分析基于 linux 4 14 132 上游代码 运行环境为 Ubuntu 16 04 4 LTS QEMU Arm vexpress a
  • HTTP参数污染攻击

    服务器两层架构 服务器端有两个部分 第一部分为tomcat为引擎的jsp型服务器 第二部分为apache为引擎的php服务器 真正提供web服务器的是php服务器 工作流程为 client访问服务器能直接访问到tomcat服务器 然后tom
  • SQL注入系列之ASP+ACCESS手动注入(一)----数字型

    一 access数据库 1 简介 Microsoft Office Access是由微软发布的关系数据库管理系统 它结合了 MicrosoftJet Database Engine 和 图形用户界面两项特点 是 Microsoft Offi
  • 分类模块丨前端uniapp微信小程序项目

    小兔鲜儿 分类模块 用户点击左菜单的一级分类 切换右侧对应的二级分类和商品 准备工作 参考效果 商品分类页中的广告位 可复用之前定义的轮播图组件 XtxSwiper 静态结构 商品分类页静态结构 src pages category cat
  • 拷贝构造(深拷贝、浅拷贝)

    一 概念介绍 拷贝构造 拷贝构造函数 又称构造函数 是一种特殊的构造函数 它由编译器调用来完成一些基于同一类的其他对象的构造及初始化 其唯一的形参必须是引用 但并不限制为const 一般普遍的会加上const限制 在类中如果没有显式给出拷贝
  • avalon.js 转义html,avalon模块的内建适配器

    text bindings 第一个传参将强制转换为字符串 假值为 然后变成目标节点的innerText 今天的天气为 require ready more avalon function var viewModel myMessage ob
  • OpenLayer和JSTS空间相交应用

    getAreaData DrawGeometry level const that this 多边形绘制结束后获取空间几何数据传递 获取边界 const drawExtent DrawGeometry getExtent 实例化jsts c
  • [230517] TPO71

    7102 Minoan Palaces 目录 7102 Minoan Palaces 正文 题目 Paragraph 1 问题 1 Paragraph 2 问题 2 Paragraph 3 问题 3 4 Paragraph 4 问题 5 6
  • 极速搭建Hexo博客【 CentOS7 + Node.js + Hexo + Github Pages】

    Hexo是一款流行的博客框架 基于Node js 支持Markdown语法 这篇文章记录我如何完成搭建并部署到Github Pages上 创建虚拟环境 养成隔离项目环境的好习惯 python3 m venv venv blog 创建虚拟环境
  • 三相三线与三相四线计算公式

    三相三线与三相四线计算公式 项目 计算公式 备注 视在功率 S UI 有功功率 P 3UxIxcos 3ULILcos Ux 相电压 无功功率 Q 3UxIxsin 3ULILsin UL 线电压 功率因数 cos P S P UI 总视在
  • Linux系统开发

    一 实验目的 设计一款携带多种功能的聊天软件 不仅可以聊天 也能修改字体 计时 绘画等等 二 实验内容 1 ui设计 满分15分 2 画图 timer 多线程 满分20分 3 数据库操作 满分15分 4 TCP网络通信 满分40分 客户端1