Я строю пользовательский интерфейс Сервер / Клиент.Чтобы воспроизвести проблему, я подготовил MVCE, который повторяет проблему, которая у меня есть.
Интерфейс GUI описывается следующим образом: серверный компьютер имеет QGraphicsView, где есть зеленый квадрат N.1, движущийся в пределах границ QGraphicsScene
, и препятствие.Как только квадрат попадает либо в границы, либо в препятствие, серверный компьютер должен отправить клиенту сообщение с координатами столкновения.
Для запуска примера выполните следующие шаги:
1) установить номер порта на клиенте и сервере (номер порта должен быть одинаковым)
2) подготовить сообщение для отправки с сервера на клиент
3) подключить клиент
4) Отправить сообщение с сервера клиенту
5) Подождите, пока квадрат не достигнет границы или препятствия
6) Как только это произойдет, сервер долженотправить координаты столкновения клиенту.(Я застрял в этом последнем пункте)
См. Рисунок ниже, который описывает
Что я пытался до сих пор :
Похоже, что с этого сообщения должен быть приоритет сообщений, отправляемых с / на серверный компьютер.Однако я могу успешно отправлять сообщения с сервера на клиент.
Также в соответствии с этот источник , чтобы не потерять информацию о том, что должно быть установлено более одной дейтаграммы.
Дополнительно всегда из того же поста UDP против TCP может быть основной причиной потери данных.
См. Ниже код, который повторяет проблему :
Клиент UDP
widget.h
namespace Ui {
class Widget;
}
class QUdpSocket;
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_connectBtn_clicked();
private:
Ui::Widget *ui;
QUdpSocket *mSocket;
};
#endif // WIDGET_H
widget.cpp
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
mSocket = new QUdpSocket(this);
setWindowTitle("Client Machine");
connect(mSocket, &QUdpSocket::readyRead, [&]() {
if(mSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(mSocket->pendingDatagramSize());
mSocket->readDatagram(datagram.data(), datagram.size());
ui->listWidget->addItem(QString(datagram));
}
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_connectBtn_clicked()
{
mSocket->bind(ui->portSpinBoxClient->value(), QUdpSocket::ShareAddress);
}
UDP-сервер
widget.h
#include <QWidget>
#include <QGraphicsItem>
namespace Ui {
class Widget;
}
class QUdpSocket;
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_sendBtn_clicked();
void on_pushButton_clicked();
private:
Ui::Widget *ui;
QUdpSocket *mSocket;
QGraphicsScene *scene;
QTimer *timer;
QGraphicsRectItem *itemRect;
#endif // WIDGET_H
widget.cpp
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
mSocket = new QUdpSocket(this);
setWindowTitle("Server Machine");
scene = new QGraphicsScene(this);
itemRect = new QGraphicsRectItem();
ui->graphicsView->setScene(scene);
ui->graphicsView->setRenderHint(QPainter::Antialiasing);
scene->setSceneRect(-200, -200, 300, 300);
QBrush darkBrush(Qt::darkRed);
QPen darkRedPen(Qt::darkRed);
itemRect = scene->addRect(-100, -100, 30, 100, darkRedPen, darkBrush);
itemRect->setFlag(QGraphicsItem::ItemIsMovable);
QPen myPen = QPen(Qt::red);
QLineF TopLine(scene->sceneRect().topLeft(), scene->sceneRect().topRight());
QLineF LeftLine(scene->sceneRect().topLeft(), scene->sceneRect().bottomLeft());
QLineF RightLine(scene->sceneRect().topRight(), scene->sceneRect().bottomRight());
QLineF Bottom(scene->sceneRect().bottomLeft(), scene->sceneRect().bottomRight());
scene->addLine(TopLine, myPen);
scene->addLine(LeftLine, myPen);
scene->addLine(RightLine, myPen);
scene->addLine(Bottom, myPen);
int itemCount = 1;
for(int i = 0; i < itemCount; i++) {
MyItem *item = new MyItem();
scene->addItem(item);
}
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), scene, SLOT(advance()));
timer->start(100);
ui->pushButton->setStyleSheet("QPushButton{ background-color: grey }");
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_sendBtn_clicked()
{
auto datagram = ui->msgLineEdit->text().toLatin1();
mSocket->writeDatagram(datagram, QHostAddress::Broadcast,ui->spinBox->value());
}
void Widget::on_pushButton_clicked()
{
ui->pushButton->setStyleSheet("QPushButton{ background-color: green }");
ui->pushButton->setText("Stop");
}
И, наконец, класс, в котором обнаруживаются сталкивающиеся объекты:
myitem.h
class MyItem : public QGraphicsItem
{
public:
MyItem();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
protected:
void advance(int phase);
private:
qreal angle;
qreal speed;
void doCollision();
};
#endif // MYITEM_H
myitem.cpp
#include "myitem.h"
MyItem::MyItem()
{
angle = (qrand() % 360);
setRotation(angle);
speed = 5;
int startX = 0;
int startY = 0;
if((qrand() % 1)){
startX = (qrand() % 200);
startY = (qrand() % 200);
}else{
startX = (qrand() % -100);
startY = (qrand() % -100);
}
setPos(mapToParent(startX, startY));
}
QRectF MyItem::boundingRect() const
{
return QRect(0, 0, 30, 30);
}
void MyItem::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
QRectF rec = boundingRect();
QBrush brush(Qt::gray);
if(scene()->collidingItems(this).isEmpty()){
brush.setColor(Qt::green); // no collision
}else{
brush.setColor(Qt::red); // yes collision
doCollision();
}
painter->fillRect(rec, brush);
painter->drawRect(rec);
}
void MyItem::advance(int phase)
{
if(!phase) return;
QPointF location = this->pos();
setPos(mapToParent(0, -(speed)));
}
void MyItem::doCollision()
{
if((qrand() %1)) {
setRotation(rotation() + (180+(qrand() % 10)));
}else{
setRotation(rotation() + (180+(qrand() % -10)));
}
// see if the new position is in bounds
QPointF newPoint = mapToParent(-(boundingRect().width()), -(boundingRect().width() + 2));
if(!scene()->sceneRect().contains((newPoint))){
newPoint = mapToParent(0, 0); // move it back in bounds
}else{
setPos(newPoint); // set new position
}
}
Ожидаемый результат : После того, как зеленый квадрат достигнет границ QGraphicsScene
или объекта, координаты столкновения должны быть отправлены клиенту.
Фактический результат : Как отправить координаты столкновения вКлиент?
Есть идеи о том, какДля решения этой проблемы было бы очень полезно.