C++ ----Qt

1.什么是QT

Qt是一个跨平台的C++应用程序开发框架。

用于开发图形用户界面、嵌入式系统、以及其他应用程序(嵌入式,桌面,汽车中控),支持Windows、macOS、Linux、Android和iOS等多个操作系统。

Qt框架提供了丰富的功能和工具,包括图形用户界面设计、数据库操作、网络编程、文件处理等。

它还包括了一个广泛的类库,开发者可以使用这些类来加速应用程序的开发过程。Qt还具有良好的文档和社区支持,因此广泛用于各种类型的应用程序开发,包括桌面应用、移动应用、嵌入式系统等。

2.QT父子关系

  • 父子关系的建立

通过在对象的构造函数中传递父对象的指针,可以建立父子关系。QObject的子类通常在构造函数中传入父对象指针,以建立父子关系,这样父对象会负责管理子对象的内存。

MyChildClass::MyChildClass(QObject *parent): QObject(parent) {// 构造函数中传入父对象指针
}
  • 父子关系的影响

当父对象被销毁时,它的所有子对象也会被自动销毁。 父对象的位置和大小变化也会影响到子对象。

  • Qobject的parent()函数

通过parent()函数可以获取对象的父对象指针

QObject *parent = myObject->parent();
  • 父子关系的使用范围

父子关系通常在GUI编程中用得比较多,例如窗口和窗口上的控件之间建立父子关系。 父子关系在对象的内存管理方面非常有用,能够简化内存释放的过程。

  • Qobject的findChild函数

  • 通过findChild函数可以在父对象的子对象中查找特定名称的子对象。

QObject *childObject = parentObject->findChild<QObject*>("childObjectName");
  • 事件传递中的父子关系

在事件传递中,父子关系也很重要。事件通常从父对象传递到子对象,父对象可以拦截事件,也可以选择传递给子对象处理。

bool MyObject::event(QEvent *event) {if (event->type() == QEvent::KeyPress) {// 处理键盘事件return true;}return QObject::event(event); // 默认事件处理方式
}
  • QT对象树模型

一个QObject对象可以有一个父对象和多个子对象。

Qt的对象树模型是一种递归的结构,其中一个对象可以拥有多个子对象,而每个子对象又可以拥有自己的子对象。

在对象树模型中,父对象的销毁会导致所有子对象的自动销毁。当一个QObject对象被销毁时,它的所有子对象也会被递归地销毁。

3.信号与槽机制

信号:点击一个按钮时,发出一个信号

槽:程序会执行一段代码逻辑,槽函数

3.1信号与槽的实现
  • 点击按钮,右击,转到槽,新增了on_commitButton_clicked()函数

void Widget::on_commitButton_clicked(){//获取lineedit数据QString program = ui->cmdLineEdit->text();//启动一个进程:process对象QProcess *myProcess = new QProcess(this);myProcess->start(program);
}
  • 信号与槽进行关联:发出一个信号,调用这个函数

//参数:谁发出信号   发出什么信号  谁处理信号  怎么处理
connect(ui->cmdLineEdit,SIGNAL(returnPressed()),this,SLOT(on_commitButton_clicked()));
//SIGNAL(returnPressed()):点回车也有反应
  • 地址的形式写

void Widget::on_cancelButton_clicked(){this->close();
}
//取消按钮,发出点击信号,当前对象处理信号,怎么处理:关闭
connect(ui->cancelButton,&QPushButton::clicked,this,&Widget::on_cancelButton_clicked);
  • lambda表达式

#include<QMessageBox>
connect(ui->browseButton,&QPushButton::clicked,[this](){//跳出一个对话框QMessageBox::information(this,"信息","点击浏览");
});

4.QMainWindow

QMainWindow用于创建应用程序的主窗口,他提供了一个标准的应用程序主窗口结构。

包括:菜单栏、工具栏、状态栏、停靠部件、中心部件

4.1菜单栏QMenuBar

菜单栏包含多个菜单,在菜单中包含菜单项 菜单栏--->菜单(File) ---->菜单项(open)

头文件

#include<QMenuBar>
#include<QMenu>
#include<QAction>
  • 创建菜单栏

QMenuBar *menuBar = new QMenuBar(this);
  • 在菜单栏上添加一个菜单File

QMenu *fileMenu = menuBar->addMenu(tr(File));
  • 在菜单中添加菜单项open

QAction *openAction = new QAction(tr("Open"),this);
fileMenu->addAction(openAction);
connect(openAction,SIGNAL(triggered()),this,SLOT(openfile()));//openfile()是槽函数,当菜单项被点击时执行相应操作                                                                  triggered() 信号会在用户点击菜单项open时发出。
setMenuBar(menuBar);
4.2工具栏QToolBar

头文件

#include<QToolBar>
  • 创建一个工具栏

QToolBar *toolBar = new QToolBar("MyToolBar",this);
addToolBar(toolBar);
  • 在工具栏上添加按钮

QAction *openAction = new QAction(QIcon("open.png"), "Open", this);
connect(openAction, SIGNAL(triggered()), this, SLOT(openFile()));
toolBar->addAction(openAction);

这里,open.png 是按钮的图标文件。openFile() 是一个槽函数,当按钮被点击时执行相应的操作。

4.3状态栏QStatusBar
  • 创建状态栏

使用statusBar()函数来获取当前状态栏对象

  • 添加标签或消息到状态栏

statusBar()->showMessage("Ready",3000);//在状态栏上显示消息,持续消息3m
  • 在状态栏上添加控件

QLabel *statusLabel = new QLabel("Status Label", this);
statusBar()->addPermanentWidget(statusLabel);

5.QT定时器

实现定时器:

  • QObject:开启定时器startTimer; 结束定时器 KillTimer

  • Qtimer

5.1QObject定时器

实现照片的轮询显示

#define WIDGET_H
​
#include <QWidget>
​
QT_BEGIN_NAMESPACE
#define TIMEOUT 1*1000
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
​
class Widget : public QWidget
{Q_OBJECT
​
public:Widget(QWidget *parent = nullptr);//虚函数,定义事件virtual void timerEvent(QTimerEvent *event);~Widget();
​
private slots:void on_statarButton_clicked();void on_stopButton_clicked();
private:Ui::Widget *ui;int myTimerId;//定时器IDint pixId;//照片ID
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
​
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//照片IDpixId=2;//程序启动的时候,显示一张图片QPixmap pix("D:\\myQt\\qtProject\\QObjectTimer\\img\\1.jpeg");//显示ui->label->setPixmap(pix);
}
//event:获取当前定时器的编号
//计时一秒钟时间到了之后,就会执行这个事件
void Widget::timerEvent(QTimerEvent *event)
{//判断是否是这个定时器if(event->timerId()!=myTimerId)return;//路径QString path("D:\\myQt\\qtProject\\QObjectTimer\\img\\");path+=QString::number(pixId);path+=".jpeg";//显示QPixmap pix(path);ui->label->setPixmap(pix);pixId++;if(5==pixId){pixId = 1;}
}
Widget::~Widget()
{delete ui;
}
//开始按钮
void Widget::on_statarButton_clicked()
{//开启定时器,返回定时器的编号myTimerId = this->startTimer(TIMEOUT);
}
//取消按钮
void Widget::on_stopButton_clicked()
{this->killTimer(myTimerId);
}
5.2QTimer定时器

开始:start()

结束:stop()

#ifndef WIDGET_H
#define WIDGET_H
​
#include <QWidget>
#include<QTimer>
#define TIMEOUT 1*1000
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_startButton_clicked();void timeOutSlots();void on_stopButton_clicked();void on_SingButton_clicked();
​
private:Ui::Widget *ui;QTimer* timer;int pixId;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
​
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建timer对象timer = new QTimer();pixId = 2;//显示图片QImage img;img.load("D:\\myQt\\qtProject\\QObjectTimer\\img\\1.jpeg");ui->label->setPixmap(QPixmap::fromImage(img));
​//定时器时间到,发出timeout信号connect(timer,&QTimer::timeout,this,&Widget::timeOutSlots);
}
​
Widget::~Widget()
{delete ui;
}
​
void Widget::on_startButton_clicked()
{//开启定时器timer->start(TIMEOUT);
}
//事件
void Widget::timeOutSlots()
{//切换图片QString path("D:\\myQt\\qtProject\\QObjectTimer\\img\\");path+=QString::number(pixId);path+=".jpeg";QImage img;img.load(path);ui->label->setPixmap(QPixmap::fromImage(img));pixId++;if(5==pixId){pixId = 1;}
​
}
//解释计时
void Widget::on_stopButton_clicked()
{timer->stop();
}
//单次
void Widget::on_SingButton_clicked()
{QTimer::singleShot(1000,this,SLOT(timeOutSlots()));
}

6.QT文件操作

6.1文件和目录读写操作

在Qt中,文件和目录的读写操作主要使用QFileQDir

6.1.1文件的读写操作

1.写文件

使用QFile类进行文件的写操作。首先,创建一个QFile对象,然后打开文件并使用QTextStream类进行写入操作。

QFile file("example.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {QTextStream out(&file);out << "Hello, World!";file.close();
}

2.读文件

使用QFile类进行文件的读操作。打开文件后,可以使用QTextStream类逐行读取文本内容。

QFile file("example.txt");
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {QTextStream in(&file);QString line = in.readLine();qDebug() << "Read from file: " << line;file.close();
}
6.1.2目录的操作

1.创建目录

使用QDir类创建目录。如果目录已存在,mkdir()函数会返回false。

QDir directory;
if (!directory.mkdir("myDirectory")) {qDebug() << "Failed to create directory!";
}

2.遍历目录

使用QDir类的entryList()函数可以获取目录下的文件列表

QDir directory("myDirectory");
QStringList files = directory.entryList(QDir::Files);
qDebug() << "Files in directory: " << files;

3.删除目录

使用QDir类的rmdir()函数可以删除目录。请注意,目录必须为空才能被成功删除。

QDir directory("myDirectory");
if (directory.exists() && directory.rmdir(".")) {qDebug() << "Directory deleted successfully!";
} else {qDebug() << "Failed to delete directory!";
}
6.2二进制文件读写
6.2.1二进制文件写入

1.打开文件

使用QFile类打开一个文件,指定QIODevice::WriteOnly标志表示以写入方式打开文件。

QFile file("data.bin");
if (file.open(QIODevice::WriteOnly)) {QDataStream out(&file); // 使用QDataStream关联QFile对象
}

2.写入数据

使用<<操作符将数据写入到QDataStream中。QDataStream会自动处理数据的序列化。

int intValue = 42;
double doubleValue = 3.14;
QString stringValue = "Hello, World!";
​
out << intValue << doubleValue << stringValue;

3.关闭文件

file.close();
6.2.2二进制文件的读取

1.打开文件

使用QFile类打开已有的二进制文件,指定QIODevice::ReadOnly标志表示以只读方式打开文件。

QFile file("data.bin");
if (file.open(QIODevice::ReadOnly)) {QDataStream in(&file); // 使用QDataStream关联QFile对象
}

2.读取文件

使用>>操作符将数据从QDataStream中读取。QDataStream会自动处理数据的反序列化。

int intValue;
double doubleValue;
QString stringValue;
​
in >> intValue >> doubleValue >> stringValue;

3.关闭文件

file.close();
6.3利用MainWindow和文件读写实现一个编辑器
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
​
#include <QMainWindow>
#include<QFileDialog>
#include<QString>
#include<QMessageBox>
#include<QDebug>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
​
class MainWindow : public QMainWindow
{Q_OBJECT
​
public:MainWindow(QWidget *parent = nullptr);~MainWindow();
private slots:void newWindowSlot();void openWindowSlot();void saveWindowSlot();
private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
​
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//连接槽函数connect(ui->newWindow,&QAction::triggered,this,&MainWindow::newWindowSlot);connect(ui->openWidow,&QAction::triggered,this,&MainWindow::openWindowSlot);connect(ui->saveWindow,&QAction::triggered,this,&MainWindow::saveWindowSlot);
}
​
MainWindow::~MainWindow()
{delete ui;
}
//新建记事本
void MainWindow::newWindowSlot()
{ui->textEdit->clear();this->setWindowTitle("新建文本文档");
}
//打开记事本
void MainWindow::openWindowSlot()
{//点打开,弹出对话框getOpenFileName(对话框的父类,标题,路径,显示的文件类型)//QCoreApplication::applicationFilePath():获取当前路径QString fileName = QFileDialog::getOpenFileName(this,"选择一个文件",QCoreApplication::applicationFilePath(),"*.cpp");//如果文件名为空,则表示取消if(fileName.isEmpty()){QMessageBox::warning(this,"警告","请选择一个文件");}else{// qDebug() << fileName;//打开文件,创建文件对象QFile file(fileName);//只读file.open(QIODevice::ReadOnly);QByteArray ba = file.readAll();//显示到界面ui->textEdit->setText(QString(ba));file.close();}
}
//另存为
void MainWindow::saveWindowSlot()
{QString fileName = QFileDialog::getSaveFileName(this,"选择一个文件",QCoreApplication::applicationFilePath());if(fileName.isEmpty()){QMessageBox::warning(this,"警告","请选择一个文件");}else{//打开文件,创建文件对象QFile file(fileName);//只写file.open(QIODevice::WriteOnly);
​QByteArray ba;//转换为QByteArray类型QByteArray a = ui->textEdit->toPlainText().toUtf8();ba.append(a);
​file.write(ba);file.close();}
}
6.4QT事件实现文件保存

QT事件类型如下:键盘事件,鼠标事件、拖放事件、滚动事件、绘屏事件、定时事件、焦点事件。

QT将系统产生的消息转化为QT事件,QT事件被封装为对象,所有的QT事件均继承抽象类QEvent,用于描述程序内部或外部发生的动作,任意的QObject对象都具备处理QT事件的能力。

event()函数是虚函数,重写event虚函数实现功能。

1.键盘事件

首先,重写虚函数keyPressEvent();

void keyPressEvent(QKeyEvent *k);

然后,实现虚函数

void MainWindow::keyPressEvent(QKeyEvent *k){//判断ctrl+S键被按下   //modifiers哪些热键被按下了,controlModifier:ctrl键 Key_S:S键被按下了if(k->modifiers()==Qt::controlModifier && k->key()==Qt::Key_S){saveWindowsSlot();}
}

keyReleaseEvent(QKeyEvent *event):处理按键释放事件

2.鼠标事件

首先,重写虚函数mousePressEvent();

void mousePressEvent(QMouseEvent *m);

然后,实现虚函数

void mousePressEvent(QMouseEvent *m){//获取鼠标位置QPoint pt = m->pos();qDebug() <<qt;//鼠标左键if(m->button()==Qt::LeftButton){qDebug() << "左键被按下";}//鼠标右键else if(m->button()==Qt::RightButton){qDebug() <<"右键被按下";}
}
mouseReleaseEvent(QMouseEvent *m)//处理鼠标按键释放事件
​
mouseMoveEvent(QMouseEvent *m)//处理鼠标移动事件

3.定时器事件

定时器事件是在一定的事件间隔内周期性触发的事件

void MyWidget::timerEvent(QTimerEvent *event){qDebug() <<"Timer Event Triggered!";
}

7.Qt网络--TCP

6.1TCP客户端

头文件

#include<QTcpSocket>
#include<QHostAddress>

1.创建socket对象

QTcpSocket *socket;
socket = new QTcpSocket;

2.获取ip地址和端口号

QString ip = ui->ipLineEdit->text();
QString port = ui->portLineEdit->text();

3.连接服务器

socket->connectToHost(QHostAddress(ip),port.toShort());

4.判断是否连接成功

connect(socket,&QTcpSocket::connected,[this](){QMessageBox::information(this,"连接提示","连接服务器成功");
});

5.断开连接也要发出信号

connect(socket,&QTcpSocket::disconnected,[this](){QMessageBox::information(this,"警告","与服务器断开");
});
6.2TCP服务端

头文件

#include<QTcpServer>
#include<QTcpSocket>
#include<QHostAddress>

1.创建server对象

QTcpServer *server;
server = new QTcpServer;

2.监听,不需要绑定

server->listen(QHostAddress::AnyIPv4,8000);//监听任意ipv4地址,端口号8000

3.客户端发起连接,server发起信号

connect(server,&QTcpServer::newConnection.this,&Widget::newClientHandle);//tcp建立一个新的连接

4.创建TCP连接

void Widget::newClientHandle(){//建立TCP连接QTcpSocket *socket = server->nextPendingConnect();//显示ui->iplineEdit->setText(socket->peerAddress().toString());ui->portlineEdit->setText(QString::number(socket->peerPort());
}
6.3QT页面跳转

1.首先创建一个新的界面chat.ui

2.在判断是否连接成功后,首先要隐藏之前的界面

this->hide();

3.然后进行页面跳转

chat* c = new chat(socket);
c->show();

4.在chat.h中,添加有参构造的参数

explicit chat(QTcpSocket *s,QWidget *parent = nullptr);
private:QTcpSocket *socket;
chat(QTcpSocket *s,QWidget *parent){socket = s;
}

客户端发送消息

void chat::on_sendButton_clicked(){QByteArray ba;ba.append(ui->lineEdit->text().toUtf8);socket->write(ba);
}

服务器接收消息

1.服务器接收到客户端收到的消息,socket发出readyread信号

connect(socket,&QTcpSocket::readyRead,this,&Widget::clientInfoSolt);

2.clientInfoSolt处理信号

void Widget::clientInfoSolt(){//获取信号的发出者QTcpSocket *s = (QTcpSocket *)sender();//显示消息到界面ui->clientLineEdit->setText(QString(s.readAll()));
}
6.4服务器中加入多线程

1.方式一错误 socket对象不能跨线程使用

1.首先创建线程类mythread.h和mythread.cpp

void myThread::run(){connect(socket,&QTcpSocket::readyRead,this,&myThread::clientInfoSolt);
}
void myThread::clientInfoSolt(){qDebug() << socket->readAll();
}

2.在创建TCP连接之后,开启线程,线程进行连接操作

myThread *t = new myThread(socket);
t->start();

2.方式二

socket对象不能跨线程使用,但是文件描述符可以

所以将socket对象转换成文件描述符传过去,然后在线程中再转换为sokcet

1.头文件

#include<QThread>

2.创建MyTcpServer类,这个类是继承QTcpServer类的

3.然后在MyTcpServer类中重写虚函数incomingConnection。

用来创建线程对象和事件对象,并建立线程和事件之间的联系,线程启动。

连接clienthander类里面的working()槽函数

//有客户端连接,会触发该函数
void MyTcpServer::incomingConnection(qintptr socketDescriptor){
​QThread *subThread = new QThread; //线程对象ClientHandler *myClient = new ClientHandler(socketDescriptor); //事件对象  把文件描述符传进去myClient->moveToThread(subThread); //将事件添加到线程中subThread->start(); //启动线程connect(this,&MyTcpServer::signal_to_thread,myClient,&ClientHandler::working);//myClient这个事件来处理                                                                                         workingemit signal_to_thread();//发送信号  这个信号是自定义的信号,让clienthander类收到这个信号
}
​

4.实现working函数

void ClientHandler::working(){socket = new QTcpSocket;//创建socket对象socket->setSocketDescriptor(socketDescriptor);//将文件描述符添加到socket对象connect(socket,&QTcpSocket::readyRead,this,&ClientHandler::recvInfo);//连接recvInfo
}
void recvInfo(){qDebug() << socket->readAll();  //读出来
}

6.5自定义信号

在线程里操作不了UI,因此

将读出来的信息 socket->readAll()发送到ui窗口显示

不同对象之间进行通信。线程间通信

1.线程首先将数据读出来了,然后放到QByteArray里面

QByteArray ba = socket->readAll();

2.利用emit 发送信号

signals:void sendToWidget(QByteArray b);
emit sendToWidget(ba);

3.widget.cpp做连接

connect(t,&myThread::sendToWiget,this,&Widget::threadSolt);
void Widget::threadSolt(QByteArray b){ui->mainLineEdit->setText(QString(b));
}
6.6.代码

TCP客户端:

widget.h:
#ifndef WIDGET_H
#define WIDGET_H
​
#include <QWidget>
#include<QTcpSocket>
#include<QHostAddress>
#include<QMessageBox>
#include<chat.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_cancelButton_clicked();
​void on_connectButton_clicked();
​
private:Ui::Widget *ui;QTcpSocket *socket;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
​
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建socket对象socket = new QTcpSocket;
}
Widget::~Widget()
{delete ui;
}
void Widget::on_cancelButton_clicked()
{this->close();
}
void Widget::on_connectButton_clicked()
{//获取IP地址和端口号QString ip = ui->ipLineEdit->text();QString port = ui->portLineEdit->text();//连接服务器socket->connectToHost(QHostAddress(ip),port.toShort());//判断是否连接成功connect(socket,&QTcpSocket::connected,[this](){QMessageBox::information(this,"连接提示","连接服务器成功");//隐藏之前的页面this->hide();//页面跳转chat* c = new chat(socket);c->show();});//连接断开也会发出信号connect(socket,&QTcpSocket::disconnected,[this](){QMessageBox::warning(this,"警告","与服务器断开");});
}
chat.h:
#ifndef CHAT_H
#define CHAT_H
​
#include <QWidget>
#include<QTcpSocket>
namespace Ui {
class chat;
}
​
class chat : public QWidget
{Q_OBJECT
​
public:explicit chat(QTcpSocket *s,QWidget *parent = nullptr);~chat();
​
private slots:void on_clearButton_clicked();
​void on_sendButton_clicked();
​
private:Ui::chat *ui;QTcpSocket *socket;
};
​
#endif // CHAT_H
chat.cpp:
#include "chat.h"
#include "ui_chat.h"
​
chat::chat(QTcpSocket *s, QWidget *parent): QWidget(parent), ui(new Ui::chat)
{ui->setupUi(this);socket = s;
}
​
chat::~chat()
{delete ui;
}
//取消
void chat::on_clearButton_clicked()
{ui->lineEdit->clear();
}
//发送
void chat::on_sendButton_clicked()
{QByteArray ba;ba.append(ui->lineEdit->text().toUtf8());socket->write(ba);
}

TCP服务端:

myThread.h:
#ifndef MYTHREAD_H
#define MYTHREAD_H
​
#include <QObject>
#include<QThread>
#include<QTcpSocket>
#include<QDebug>
class myThread : public QThread
{Q_OBJECT
public:explicit myThread(QTcpSocket *s);void run();
signals:void sendToWidget(QByteArray b);
private slots:void clientInfoSlot();
private:QTcpSocket *socket;
};
​
#endif // MYTHREAD_H
myThread.cpp:
#include "mythread.h"
​
myThread::myThread(QTcpSocket *s){socket = s;
}
void myThread::run()
{//连接connect(socket,&QTcpSocket::readyRead,this,&myThread::clientInfoSlot);
}
void myThread::clientInfoSlot()
{//接收,打印// qDebug() << socket->readAll();QByteArray ba = socket->readAll();//发送emit sendToWidget(ba);
}
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
​
#include <QWidget>
#include<QTcpServer>
#include<QTcpSocket>
#include<mythread.h>
#define PORT 8000
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 newClientHandle();void clientInfoSolt();void threadSolt(QByteArray b);
private:Ui::Widget *ui;QTcpServer *server;
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
#include "ui_widget.h"
​
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建server对象server = new QTcpServer;//监听就可以了,不需要绑定server->listen(QHostAddress::AnyIPv4,PORT);//客户端发起连接,server发起信号connect(server,&QTcpServer::newConnection,this,&Widget::newClientHandle);
}
​
Widget::~Widget()
{delete ui;
}
​
void Widget::newClientHandle()
{//创建TCP连接QTcpSocket *socket = server->nextPendingConnection();// socket->peerAddress();//客户端地址// socket->peerPort();//客户端端口号ui->iplineEdit->setText(socket->peerAddress().toString());ui->portlineEdit->setText(QString::number(socket->peerPort()));
​//服务器接收到客户端收到的消息,socket发出readyread信号// connect(socket,&QTcpSocket::readyRead,this,&Widget::clientInfoSolt);//开启线程myThread* t = new myThread(socket);t->start();connect(t,&myThread::sendToWidget,this,&Widget::threadSolt);
}
​
void Widget::threadSolt(QByteArray b)
{ui->clientLineEdit->setText(QString(b));
}
​
// void Widget::clientInfoSolt()
// {
//     //获取信号的发出者
//     QTcpSocket *s = (QTcpSocket *)sender();
//     //显示消息到界面
//     ui->clientLineEdit->setText(QString(s->readAll()));
// }

8.QTmySql数据库操作

头文件

#include<QSqlDatabase>
QSqlDatabase db;
1.连接数据库
db = QSqlDatabase::addDatabase("QMYSQL");//连接mysql数据库
db.setDatabaseName("mydatabase"); //数据库名
db.setHostName("localhost");//本机地址
db.setUserName("root");//用户名
db.setPassword("root");//密码
if(db.open()){QMessageBox::information(this,"连接提示","连接成功");
}
else{QMessageBox::information(this,"连接提示","连接失败");
}
2.插入数据库
QString id = ui->idLineEdit->text();
QString name = ui->nameLineEdit->text();
QString birth = ui->birLineEdit->text();
//数据库
QString sql = QString("insert into student values ('%1','%2','%3');").arg(id).arg(name).arg(birth);
QSqlQuery query;
//插入数据
if(query.exec(sql)){QMessageBox::information(this,'插入提示','插入成功');
}
else{QMessageBox::information(this,'插入提示','插入失败');
}
3.查询
QSqlQuery query;
query.exec("select * from student;");
while(query.next()){qDebug() << query.value(0);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/55479.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ChatGPT】如何让 ChatGPT 理解多步骤指令

如何让 ChatGPT 理解多步骤指令 在与 ChatGPT 交互时&#xff0c;多步骤指令能够帮助模型更准确地理解复杂任务并逐步执行每个步骤。然而&#xff0c;如果多步骤指令没有清晰组织&#xff0c;可能会导致输出混乱或不完整。本文将介绍如何有效编写多步骤指令&#xff0c;使 Cha…

Docker-compose提示specified IP address..configured subnets问题以及Docker容器相关操作记录保存

一、Docker-compose提示user specified IP address is supported only when connecting to networks with user configured subnets 在网上下载的一些docker-compose.yml在执行的时碰到过多次如下报错&#xff1a; ERROR: for 5307e2acb....user specified IP address is supp…

【Flutter】Dart:环境搭建

Flutter 是一个基于 Dart 的跨平台开发框架&#xff0c;可以帮助我们快速构建移动应用程序。在开始 Flutter 开发之前&#xff0c;我们需要先搭建 Dart 的开发环境&#xff0c;并配置合适的编辑器&#xff0c;比如 VSCode。本教程将引导你一步步完成 Dart 和 Flutter 的环境搭建…

2024.10.17 软考学习笔记

刷题网站&#xff1a; 软考中级软件设计师在线试题、软考解析及答案-51CTO题库-软考在线做题备考工具

vue2项目 实现上边两个下拉框,下边一个输入框 输入框内显示的值为[“第一个下拉框选中值“ -- “第二个下拉框选中的值“]

效果: 思路: 采用vue中 [computed:] 派生属性的方式实现联动效果,上边两个切换时,下边的跟随变动 demo代码: <template><div><!-- 第一个下拉框 --><select v-model"firstValue"><option v-for"option in options" :key&q…

Github优质项目推荐 - 第六期

文章目录 Github优质项目推荐 - 第六期一、【WiFiAnalyzer】&#xff0c;3.4k stars - WiFi 网络分析工具二、【penpot】&#xff0c;33k stars - UI 设计与原型制作平台三、【Inpaint-Anything】&#xff0c;6.4k stars - 修复图像、视频和3D 场景中的任何内容四、【Malware-P…

适用于 Windows 的 4 个最佳免费数据恢复软件

计算机最重要的是用户数据。除了您的数据之外&#xff0c;关于计算机的其他一切都是可替换的。这三个是数据丢失的最常见原因&#xff1a; 文件/文件夹删除 丢失分区 损坏的分区 文件/文件夹删除是最常见的数据丢失类型。大多数时候&#xff0c;由于不小心删除文件/文件夹而…

G-Set(增长集合,Grow-Only Set)

一、概念 G-Set&#xff08;增长集合&#xff0c;Grow-Only Set&#xff09;是一种冲突自由复制数据类型&#xff08;Conflict-Free Replicated Data Type, CRDT&#xff09;&#xff0c;用于在分布式系统中同步和合并数据&#xff0c;而不需要中央协调器。G-Set 支持两种操作…

限流是什么?如何限流?怎么限流?

概述 什么是限流 对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机 为什么要限流 因为互联网系统通常都要面对大并发大流量的请求,在突发情况下(最常见的场景就是秒杀、抢购),瞬时大流量会直接将系统打垮,无法…

html和css实现页面

任务4 html文件 任务5 htm文件 css文件 任务6 html文件 css文件 任务7 html文件 css文件

Java【多线程】synchronized关键字

目录 synchronized的特性 1.互斥 2.可重入 如何自己实现一个可重入锁&#xff1f; 关于死锁 死锁的第三种情况 N个线程M把锁 构成死锁的四个必要条件 java标准库中的线程安全类 线程不安全 线程安全 synchronized关键字-监视器锁monitor locker synchronized的特性 …

Tailscale自建中转服务器derper搭建笔记(基于docker)

自己搭建derper服务器&#xff0c;让Tailscale中转更流畅。 Tailscale是很好的远程组网工具&#xff0c;在两台机器P2P打洞成功的情况下可以实现网络直连&#xff0c;但如果打洞失败就会进行数据中转&#xff0c;我们的数据要跑到国外再跑回来&#xff0c;这样速度就很慢了。 …

STGCN解读(论文+代码)

一、引言 引言部分不是论文的重点&#xff0c;主要讲述了交通预测的重要性以及一些传统方法的不足之处。进而推出了自己的模型——STGCN。 二、交通预测与图卷积 第二部分讲述了交通预测中路图和图卷积的概念。 首先理解道路图&#xff0c;交通预测被定义为典型的时间序列预测…

Axure重要元件一——动态面板

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 本节课&#xff1a;动态面板 课程内容&#xff1a;认识动态面板、动态面板基本操作 应用场景&#xff1a;特定窗口、重要交互、长页面、容器等 一、认识动态面板 动态…

DeBiFormer:带有可变形代理双层路由注意力的视觉Transformer

https://arxiv.org/pdf/2410.08582v1 摘要 带有各种注意力模块的视觉Transformer在视觉任务上已表现出卓越的性能。虽然使用稀疏自适应注意力&#xff08;如在DAT中&#xff09;在图像分类任务中取得了显著成果&#xff0c;但在对语义分割任务进行微调时&#xff0c;由可变形…

bug的定义和测试

一、软件测试的生命周期 软件测试的⽣命周期是指测试流程&#xff0c;这个流程是按照⼀定顺序执⾏的⼀系列特定的步骤&#xff0c;去保证产品 质量符合需求。在软件测试⽣命周期流程中&#xff0c;每个活动都按照计划的系统的执⾏。每个阶段有不同的 ⽬标和交付产物 需求分析…

【python+Redis】hash修改

文章目录 前请详解一、关于Update1. 语法2. 代码示例 二、完整代码 前请详解 Redis库数据 keyvalue1{“id”: 1, “name”: “xxx”, “age”: “18”, “sex”: “\u7537”}2{“id”: 2, “name”: “xxx”, “age”: “18”, “sex”: “\u5973”}3{“id”: 3, “name”: “…

软件测试面试题600多条及答案

这些问题都是软件测试领域常见的面试问题&#xff0c;以下是一些可能的答案&#xff1a; 什么是软件测试&#xff1f; 软件测试是一系列活动&#xff0c;旨在评估软件产品的质量和性能&#xff0c;以确保它符合规定的需求和标准。它包括执行程序或系统以验证其满足规定需求的过…

“探索Adobe Photoshop 2024:订阅方案、成本效益分析及在线替代品“

设计师们对Adobe Photoshop这款业界领先的图像编辑软件肯定不会陌生。如果你正考虑加入Photoshop的用户行列&#xff0c;可能会对其价格感到好奇。Photoshop的价值在于其强大的功能&#xff0c;而它的价格也反映了这一点。下面&#xff0c;我们就来详细了解一下Adobe Photoshop…

数据结构(8.2_1)——插入排序

插入排序 算法思想&#xff1a;每次将一个待排序的记录按其关键字大小插入到前面已排序好的子序列中&#xff0c;直到全部记录插入完成。 代码实现 #include <stdio.h>void InsertSort(int A[], int n) {int i, j.temp;for (i 1; i < n; i) {//将各元素插入已排好…