[ Qt串口助手上 ] : C++Qt编写串口助手+无边框窗口处理+Qt多线程接收 (上)界面设置

前言(界面编写)

有关于界面UI的设置,我没有使用qt默认的有边框的样式,而是选择了自定义的方式,也就是无边框样式,由于失去了标题栏,无法拖动窗口和最小化,最大化,关闭,因此需要重写qt相关的内置函数。由界面效果可以看到,展现的控件的边角都是有一定的弧度的,相比生硬的直角更加美观一些,本文主要介绍的是界面布局以及一些Qss样式表的内容,其他的在后面几篇文章中。

串口助手的专栏:Qt串口助手_rqtz的博客-CSDN博客

ui界面效果展示

日间模式

夜间模式

无边框设置

//设置无边框
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);    

在类的构造函数中添加后,显示出的窗口会失去边框,且无法拖动和其他操作,只能右键图标关闭程序。

重写内置函数,实现窗口拖动

窗口的拖动是在qt中的内置函数中实现的,这些函数是受保护的,因此,要实现窗口拖动的功能,需重写这些函数。

protected:
      void mouseMoveEvent(QMouseEvent *e) override;
      void mousePressEvent(QMouseEvent *e) override;
      void mouseReleaseEvent(QMouseEvent *e) override;

在类的头文件中添加上述函数,分别是鼠标移动事件鼠标按压事件鼠标释放事件

鼠标按压事件

void MainWindow::mousePressEvent(QMouseEvent *e)
{
    if(e->button() == Qt::LeftButton)
    {
        mouseflag = true;
        mousepose = e->globalPos();
        windowpose = this->geometry().topLeft();
    }
}

代码解释:

  • 首先是判断鼠标是左键按下,因为我们移动窗口的习惯通常是按左键。
  • mouseflag = true;  左键按下的标志位,后面会用到。
  • mousepose = e->globalPos(); 获取到当前的鼠标坐标,类型是QPoint.
  • windowpose = this->geometry().topLeft(); 获取当前窗口左上角的坐标,类型同样是QPoint。

鼠标移动事件

void MainWindow::mouseMoveEvent(QMouseEvent *e)
{
    if(mouseflag)
    {
        QPoint dis = e->globalPos()-mousepose;
        this->move(windowpose+dis);
    }
}

代码解释:

  • 首先是判断鼠标是左键按下的状态下,mouseflag为真时。
  • QPoint dis = e->globalPos()-mousepose;  当前的鼠标坐标相对于鼠标按压时的鼠标坐标mousepos的差值,该差值为距离坐标。
  • mousepose = e->globalPos(); 获取到当前的鼠标坐标,类型是QPoint.
  • this->move(windowpose+dis); 当前窗口this移动到的坐标位置,windowpose(移动前窗口位置坐标)+dis。

鼠标释放事件

void MainWindow::mouseReleaseEvent(QMouseEvent *e)
{
    if(e->button() == Qt::LeftButton)
        mouseflag = false;
}

代码解释:

当鼠标有按下到松开时,我们将mouseflag置为假,保证在只有左键按下时才进行移动

最终效果

重写事件过滤器函数,实现窗口控件悬停切换图片效果

最小化与最大化和关闭这些功能的实现是通过获取label控件的点击事件,通过添加事件过滤器的方法,

安装事件过滤器

由于label控件并没有点击事件,所以我们只能使用 setAttributeinstallEventFilter 来添加事件过滤器使其具有相关事件。

void MainWindow::sethoverevent()
{
    ui->close->setAttribute(Qt::WA_Hover,true);
    ui->close->installEventFilter(this);
    ui->little->setAttribute(Qt::WA_Hover,true);
    ui->little->installEventFilter(this);
    ui->large->setAttribute(Qt::WA_Hover,true);
    ui->large->installEventFilter(this);
    ui->switch_2->installEventFilter(this);
}

上述代码中的ui控件分别指的下面的label控件,本质是照片。

setAttribute(Qt::WA_Hover,true)  是指让label控件具有悬停事件

installEventFilter(this) 为控件安装事件过滤器,使其可以接受并处理所有的事件,包括悬停事件。

重写事件过滤器函数

在.h文件中添加

protected:
      bool eventFilter(QObject*obj,QEvent *e) override;

在.cpp函数中添加

bool MainWindow::eventFilter(QObject *obj, QEvent *e)
{
    if(e->type() == QEvent::HoverEnter)
    {
        emit hoverval(obj,obj->objectName());
        return  true;
    }
    else if(e->type() == QEvent::HoverLeave)
    {
        emit hoverval(obj,"mouseout");
        return true;
    }
}

其中

  • QObject *obj, QEvent *e :obj 表示一个当前控件的一个指针,可以通过访问objectname来获取他的名字,e表示当前事件的一个指针,可以通过type()来获取事件类型。
  • 信号singal : 当鼠标悬浮在控件上时,我们 发送信号  emit hoverval(obj,obj->objectName()); 当鼠标离开控件时,我们 发送信号  hoverval(obj,"mouseout")

绑定信号和槽

 connect(this,&MainWindow::hoverval,this,&MainWindow::hoveraction);

编写悬浮事件槽函数

void MainWindow::hoveraction(QObject *obj, QString name)
{
    if(name=="close") {
        ui->close->setPixmap(QPixmap(rclose).scaled(16,16));
    }
    else if (name=="little") {
        ui->little->setPixmap(QPixmap(rmostlittle).scaled(16,16));
    }
    else if (name=="large") {
        ui->large->setPixmap(QPixmap(rmostlarge).scaled(16,16));
    }

    else if (name=="mouseout") {
        ui->little->setPixmap(QPixmap(bmostlittle).scaled(16,16));
        ui->large->setPixmap(QPixmap(bmostlarge).scaled(16,16));
        ui->close->setPixmap(QPixmap(bclose).scaled(16,16));
    }
}

我们通过得到不同的控件名称,来去设置不同的图片,达到视觉效果。

最终效果

重写事件过滤器函数,实现窗口最大化,最小化和关闭

获取label的点击事件

在上述的evenfliter函数中添加   

else if(e->type() == QEvent::MouseButtonPress)
    {
        theammode_count++;
        emit clickval(obj,obj->objectName());
        return true;
    }

完整函数为

bool MainWindow::eventFilter(QObject *obj, QEvent *e)
{
    if(e->type() == QEvent::HoverEnter)
    {
        emit hoverval(obj,obj->objectName());
        return  true;
    }
    else if(e->type() == QEvent::HoverLeave)
    {
        emit hoverval(obj,"mouseout");
        return true;
    }
    else if(e->type() == QEvent::MouseButtonPress)
    {
        theammode_count++;
        emit clickval(obj,obj->objectName());
        return true;
    }

}

 绑定信号和槽

 connect(this,&MainWindow::hoverval,this,&MainWindow::clickaction);

编写点击事件槽函数

void MainWindow::clickaction(QObject *obj, QString name)
{
    if(name=="close") {
         this->close();
    }
    else if (name=="little") {
            this->showMinimized();
    }
    else if (name=="large") {
        static int num = 0;
        num++;
        if((num+1)%2==0)
           this->showFullScreen();
        else
            this->showNormal();
    }
  • 控件名称为close时: 调用close方法来关闭窗口
  • 控件名称为littel时: 调用showMinimized方法来最小化窗口
  • 控件名称为llarge时: 当点击次数和为奇数时,调用showFullScreen方法来最大化窗口,偶数时,调用showNormal方法还原窗口。

最终效果

最后夜间模式的实现方法,只需要获取控件的点击事件,在该函数中更新样式表即可。

重写paintevent事件,使窗口由四角的方形显示圆角形

void MainWindow::paintEvent(QPaintEvent *e)
{
    QBitmap bmp(this->size());
    bmp.fill();
    QPainter p(&bmp);
    p.setPen(Qt::NoPen);
    p.setBrush(Qt::black);
    p.drawRoundedRect(bmp.rect(),20,20);//像素为20的圆角
    setMask(bmp);
}

按钮圆角

这个是界面中的一个按钮的圆角设置的样式表,大家参考一下

QPushButton{
	font: 9pt "微软雅黑";
    color: #080808;
    background-color:#ffffff;
    border-color:#c3c3c3;
    border-radius: 14px;
    border-style: solid;
    border-width: 1px;
    padding: 4px;
}
QPushButton::hover {
background-color:rgb(224,238,249);
border-color: rgb(0,120,212);
}

注意:如果没有显示出来圆角,可能是你的圆角半径值border-radius过大或过小,结合border-width和padding多试试几个不同的值,直到有效果为止。

  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要用 C++ 编写 Qt 多线程聊天室,需要分为以下几个步骤: 1. 界面设计 可以使用 Qt Designer 工具来设计聊天室界面界面应该包括一个聊天记录区域、一个输入框和一个发送按钮。同时,还需要添加一个菜单栏或工具栏,用于启动或停止服务器。 2. 服务器端编写 服务器端需要监听客户端连接请求,并为每个连接请求创建一个子线程。在子线程中,需要编写处理客户端请求的代码。 ```c++ class ClientThread : public QThread { Q_OBJECT public: ClientThread(int socketDescriptor, QObject *parent = 0); protected: void run(); signals: void error(QTcpSocket::SocketError socketError); private: int socketDescriptor; }; ``` 在 `ClientThread` 类中,需要编写处理客户端请求的 `run()` 方法。 服务器端的 `main()` 方法代码如下: ```c++ int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Server server; if (!server.listen(QHostAddress::Any, 1234)) { qCritical() << "Failed to start server"; return -1; } qInfo() << "Server started"; return a.exec(); } ``` 在 `main()` 方法中,创建一个 `Server` 对象,并监听指定的 IP 地址和端口号。 3. 客户端编写 客户端需要连接服务器,并发送聊天消息。可以使用 `QTcpSocket` 类实现客户端与服务器之间的通信。 ```c++ class Client : public QObject { Q_OBJECT public: explicit Client(QObject *parent = 0); public slots: void connectToServer(QString hostName, quint16 port); void sendMessage(QString message); signals: void messageReceived(QString message); private slots: void readMessage(); void displayError(QAbstractSocket::SocketError socketError); private: QTcpSocket *tcpSocket; }; ``` 在 `Client` 类中,需要编写连接服务器、发送消息和读取消息的代码。 4. 在界面中调用服务器和客户端代码 在界面中,可以添加一个菜单栏或工具栏,用于启动或停止服务器。同时,还需要添加一个输入框和一个发送按钮,用于发送聊天消息。在发送按钮的点击事件中,调用客户端的 `sendMessage()` 方法,将消息发送给服务器。 在客户端接收到新消息时,需要发出 `messageReceived()` 信号,界面可以连接这个信号,将新消息显示在聊天记录区域中。 以上就是用 C++ 编写 Qt 多线程聊天室的基本步骤。具体实现细节可以参考 Qt 官方文档和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值