一、对象模型(对象树)
- 1、Qt引入对象树的概念,在一定程度上解决了内存问题;
- 2、当一个Q0bject对象在堆上创建的时候,Qt会同时为其创建一个对象树;
- 3、不过,对象树中对象的顺序是没有定义的;
- 4、这意味着,销毁这些对象的顺序也是未定义的;
在Qt中创建对象的时候会提供一个Parent对象指针,
下面来解释这个parent到底是干什么的。
------------------------------------------------
Q0bject是以对象树的形式组织起来的。
--------------------------------------------
当你创建一个Q0bject对象时,会看到Q0bject的构造函数接收一个
QObject指针作为参数,这个参数就是parent, 也就是父对象指针。
-------------------------------------------------------------------------------
----------------------------------------------------------------------
这相当于,在创建Q0bject对象时,可以提供一个其父对象,我们创建
的这个Q0bject对象会自动添加到其父对象的children()列表。
------------------------------------------------------------------------------
当父对象析构的时候,这个列表中的所有对象也会被析构。
(注意,这里的父对象并不是继承意义上的父类!)
---------------------------------------------------
这种机制在GUI程序设计中相当有用。
---------------------------------------------------------
例如,一个按钮有一个QShortcut (快捷键)对象作为其子对象。
当我们删除按钮的时候,这个快捷键理应被删除。
这是合理的。
--------------------------------------------------------------
QWidget 是能够在屏幕上显示的一切组件的父类。
----------------------------------------------------------------
QWidget继承自QObject,因此也继承了这种对象树关系。
一个孩子自动地成为父组件的一个子组件。
------------------------------------------------------------
因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。
例如,当用户关闭一个对话框的时候,应用程序将其删除,
那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。
事实就是如此,因为这些都是对话框的子组件。
--------------------------------------------------------------
当然,我们也可以自己删除子对象,它们会自动从其父对象列表中删除。
---------------------------------------------------------------------------------
比如,当我们删除了一个工具栏时,
其所在的主窗口会自动将该工具栏从其子对象列表中删除,
并且自动调整屏幕显示。
任何对象树中的Q0bject 对象delete 的时候,
如果这个对象有parent,则自动将其从parent 的children()列表中删除;
如果有孩子,则自动delete每一个孩子。
Qt保证没有Q0bject会被delete 两次,这是由析构顺序决定的。
二、TCP服务器
server.pro
------------------
QT += core gui network
----------------------------
widget.h
------------------
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_startBtn_clicked();
void on_senderBtn_clicked();
private:
Ui::Widget *ui;
QTcpServer* server;
QTcpSocket* socket;
};
#endif
--------------------------------
widget.cpp
---------------------
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("服务器");
this->server = new QTcpServer(this);
this->socket = new QTcpSocket(this);
connect(this->server,&QTcpServer::newConnection,[=](){
this->socket = this->server->nextPendingConnection();
ui->chatlogText->append("新的客户机连接了服务器");
connect(this->socket,&QTcpSocket::readyRead,[=](){
QString recvMsg = this->socket->readAll();
ui->chatlogText->append("客户机发来的数据:" + recvMsg);
});
connect(this->socket,&QTcpSocket::disconnected,[=](){
this->socket->deleteLater();
});
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_startBtn_clicked()
{
quint16 port = ui->port_line->text().toUShort();
this->server->listen(QHostAddress::Any,port);
ui->startBtn->setEnabled(false);
}
void Widget::on_senderBtn_clicked()
{
QString senderMsg = ui->senderText->toPlainText();
this->socket->write(senderMsg.toUtf8());
ui->senderText->clear();
}
三、TCP客户端
client.pro
--------------------
QT += core gui network
------------------------------------
widget.h
----------------------
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_connectBtn_clicked();
void on_disconnectBtn_clicked();
void on_senderBtn_clicked();
private:
Ui::Widget *ui;
QTcpSocket* socket;
};
#endif
------------------------
widget.cpp
---------------
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("客户端");
this->socket = new QTcpSocket(this);
connect(this->socket,&QTcpSocket::connected,[=](){
ui->chatTextRoom->append("已经连接上服务器");
});
connect(this->socket,&QTcpSocket::readyRead,[=](){
QString recvMsg = this->socket->readAll();
ui->chatTextRoom->append(recvMsg);
});
connect(this->socket,&QTcpSocket::disconnected,[=](){
this->socket->close();
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_connectBtn_clicked()
{
QString serverIP = ui->ip_line->text();
quint16 serverPort = ui->port_line->text().toUShort();
this->socket->connectToHost(serverIP,serverPort);
ui->connectBtn->setEnabled(false);
}
void Widget::on_disconnectBtn_clicked()
{
this->socket->close();
}
void Widget::on_senderBtn_clicked()
{
QString senderMsg = ui->userName_line->text() + ": " + ui->senderMsgText->toPlainText();
this->socket->write(senderMsg.toUtf8());
ui->senderMsgText->clear();
}
四、TCP并发服务器
------------------------------------
mytcpserver.h:
----------------
#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H
#include <QTcpServer>
#include <QTcpSocket>
class MyTcpServer : public QTcpServer
{
Q_OBJECT
public:
explicit MyTcpServer(QObject *parent = nullptr);
QList<QTcpSocket*> getSocketList();
protected:
void incomingConnection(qintptr handle) override;
signals:
void mytcpserver_signals(const QString& recvMsg);
private:
QList<QTcpSocket*> socket_list;
};
#endif
----------------------------
mytcpserver.cpp:
------------------------
#include "mytcpserver.h"
MyTcpServer::MyTcpServer(QObject *parent) : QTcpServer(parent)
{
}
QList<QTcpSocket *> MyTcpServer::getSocketList()
{
return this->socket_list;
}
void MyTcpServer::incomingConnection(qintptr handle)
{
QTcpSocket* socket = new QTcpSocket(this);
socket->setSocketDescriptor(handle);
this->socket_list.append(socket);
connect(socket,&QTcpSocket::readyRead,[=](){
QString recvMsg = socket->readAll();
emit this->mytcpserver_signals(recvMsg);
for(QTcpSocket* mysocket : this->socket_list)
{
mysocket->write(recvMsg.toUtf8());
}
});
connect(socket,&QTcpSocket::disconnected,[=](){
socket->close();
this->socket_list.removeOne(socket);
});
}
--------------------------------------------
widget.h:
--------------
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket>
#include "mytcpserver.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_startBtn_clicked();
void on_senderBtn_clicked();
private:
Ui::Widget *ui;
MyTcpServer* server;
};
#endif
--------------------------
widget.cpp:
-----------------
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("服务器");
this->server = new MyTcpServer(this);
connect(this->server,&MyTcpServer::mytcpserver_signals,[=](const QString& recvMsg){
ui->chatlogText->append(recvMsg);
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_startBtn_clicked()
{
quint16 port = ui->port_line->text().toUShort();
this->server->listen(QHostAddress::Any,port);
ui->startBtn->setEnabled(false);
}
void Widget::on_senderBtn_clicked()
{
QString senderMsg = ui->senderText->toPlainText();
for(QTcpSocket* mysocket : this->server->getSocketList())
{
mysocket->write(senderMsg.toUtf8());
}
ui->senderText->clear();
}