本文主要是Qt常用控件与基础记录
Qt程序组成有:应用程序类,窗口类
应用程序类有且仅有一个
常用其父类QAbstrackButton的信号
新建一个按钮:
QPushButton(QWidget *parent = Q_NULLPTR)
QPushButton(const QString &text, QWidget *parent = Q_NULLPTR)
QPushButton(const QIcon &icon, const QString &text, QWidget *parent = Q_NULLPTR)
常用成员函数:
设置父类:setParent(QWidget *parent)
设置位置:move(int x, int y)
设置大小:resize(int w, int h)
设置文本:setText(const QString &text)
什么情况下不需要手动回收:
互相互斥,用groupBox将每组进行分组。
可进行多选
专属信号:QCheckBox::stateChanged();//显示
设置图片和图片大小
ui->last->setIcon(QIcon(":/Image/last.png"));
ui->last->setIconSize(QSize(200,30));
可通过成员函数addItem()添加一行数据
//添加普通文本
ui->listWidget->addItem("状态栏");
//添加图标,方式1
ui->listWidget->addItem(new QListWidgetItem(QIcon(":/Fail/fail.png"),"失败"));
//添加图标,方式2()
QListWidgetItem *item = new QListWidgetItem(QIcon(":/Fail/affirm.png"), "affirm", ui->listWidget);
需要先设定表的行列
//1.指定行
ui->tableWidget->setRowCount(50);
//2.指定列
ui->tableWidget->setColumnCount(2);
//设定表头,方式1
QStringList list;
list<<"姓名"<<"性别";
//QStringList list = QStringList()<<"姓名"<<"性别";
ui->tableWidget->setHorizontalHeaderLabels(list);
//设定表头,方式2
QStringList list;
list.push_back("姓名");
list.push_back("性别");
ui->tableWidget->setHorizontalHeaderLabels(list);
将控件作为一组进行分组
带滚动条的窗口,当控件过多窗口显示不下时使用
抽屉窗口,在每一页都能添加控件
表型窗口,可切换窗口
栈窗口,需要通过其他控件来实现窗口的切换
//通过按钮切换窗口
connect(ui->musicButton,&QPushButton::clicked,ui->stackedWidget,[=](){
ui->stackedWidget->setCurrentIndex(0);});
connect(ui->moiveButton,&QPushButton::clicked,ui->stackedWidget,[=](){
ui->stackedWidget->setCurrentIndex(1);});
connect(ui->dataButton,&QPushButton::clicked,ui->stackedWidget,[=](){
ui->stackedWidget->setCurrentIndex(2);});
区别:
新建一个文本编辑框:
QTextEdit(QWidget *parent = Q_NULLPTR)
QTextEdit(const QString &text, QWidget *parent = Q_NULLPTR)
常用信号
##标签(QLabel)
可显示文字,图片,动态图片等
//设置图片
ui->testLabel->setPixmap(QPixmap(":/Fail/cancel.png"));
//设置动态图片,只能播放gif类型,不能播放mp4等格式
QMovie *movie = new QMovie(":my/mario.gif");
ui->testLabel->setMovie(movie);
movie->start();//启动播放
常用其静态成员函数(Static public members)
##QMainWindow
1.菜单栏
2.工具栏
3.浮动窗口
4.状态栏
菜单栏(QMenu):可为menu添加动作,动作为QAction类
浮动窗口(QDockWidget):在ui界面直接拖动添加,可在浮动窗口内添加控件
状态栏(statusBar):用addWidget()添加状态(常用label)
ui->statusBar->addWidget(new QLabel("ok"));
为菜单栏添加图片
ui->action_as->setIcon(QIcon(":添加的前缀+文件路径"));
非模态对话框:可以对其他窗口进行操作
模态对话框:不可以对其他窗口进行操作
QDialog dlg(this);//指定父窗口,也可不指定父窗口,不指定时为独立窗口
//显示非模态对话框
dlg.show();
//显示模态对话框
dlg.exec();//运行时,程序会阻塞,停在此处,要关闭对话框后才会继续执行
要使非模态对话框一闪而过,new一个对话框,防止随着父类一起被析构
QDialog *dlg = new QDialog(this);
dlg->show();
//设置对话框属性
dlg->setAttribute()
常用其静态成员函数(Static public members)
静态成员函数(可根据返回值来设置按下不同按钮的功能):
QMessageBox::about();
QMessageBox::critical();//错误对话框
QMessageBox::warning();//警告对话框
QMessageBox::question();
QMessageBox::information();
颜色对话框(QColorDialog):常用其静态成员函数(Static public members)
字体对话框(QFontDialog):常用其静态成员函数(Static public members)
ps.打印QString类型:font.family().toUtf8().data()
inf: 每个控件都应该进行布局,否则容易被遮挡,显示不出来或显示不全
技巧:布局可以先添加副窗口,然后再将副窗口内进行布局。
添加弹簧可以让窗口发生拉伸时,相对位置不发生变化,还可以设置弹簧为fixed类型,然后设置为固定宽度。
对于使用率较高的功能,可以封装为一个控件(类)。
//将滑动条与旋钮控件链接起来
int min =0;
int max = 1000;
ui->horizontalSlider->setRange(min,max);
ui->spinBox->setRange(min,max);
void(QSpinBox::*SigValueChange)(int) = &QSpinBox::valueChanged;
connect(ui->horizontalSlider, &QSlider::valueChanged, ui->spinBox, &QSpinBox::setValue);
connect(ui->spinBox,SigValueChange,ui->horizontalSlider,&QSlider::setValue);
鼠标键盘事件在继承的虚函数中(Reimplemented Protected Functions)
新建一个c++类,并继承对应的控件类,之后将对应的控件提升为新建的C++类,之后即可在新建的C++类中对该控件进行事件处理。
//继承自Widget类.h文件中声明
protected:
//鼠标进入
void enterEvent(QEvent *);
//鼠标离开
void leaveEvent(QEvent *);
//鼠标按下
void mousePressEvent(QMouseEvent *ev);
//鼠标释放
void mouseReleaseEvent(QMouseEvent *ev);
//鼠标移动
void mouseMoveEvent(QMouseEvent *ev);
//定时器
void timerEvent(QTimerEvent *);
/**************实现**********************/
//.cpp文件中的实现
void MyLabel::enterEvent(QEvent *)
{
setText("进来了");
}
void MyLabel::leaveEvent(QEvent *)
{
setText("你离开了");
}
//鼠标按下
void MyLabel::mousePressEvent(QMouseEvent *ev)
{
//"%1,%2,%3"为占位符,对应后面的第几个arg
if(ev->button() == Qt::RightButton){
QString str = QString("mouseLeftPres(%1,%2)").arg(ev->x()).arg(ev->y());
setText(str);
}
}
//鼠标移动,持续状态使用buttons()函数,
void MyLabel::mouseMoveEvent(QMouseEvent *ev)
{
QString btn;
if(ev->buttons() & Qt::RightButton){
btn = "RightButton";
}
else if(ev->buttons() & Qt::LeftButton)
{
btn = "LeftButton";
}
else if(ev->buttons() & Qt::MidButton)
{
btn = "MidButton";
}
QString str = QString("%3:(%1,%2)").arg(ev->x()).arg(ev->y()).arg(btn);
setText(str);
}
如果需要实时检测鼠标事件(默认不实时追踪),则需要在窗口构造函数中,设置窗口实时追踪鼠标事件
this->setMouseTracking(true);
声明如上所示
//方法一
//启动定时器,每过xx时间则加1,如需要使用两个定时器则启动两个定时器即可,通过id来访问不同定时器
//参数1:定时器的时间,单位ms
//参数2:默认
//返回值:定时器id
id = startTimer(100);
//关闭定时器
killTimer(id);
//方法二,常用
//包含QTimer头文件
QTimer *timer = new QTimer(this);
timer->start(100);//每100ms触发一次信号
connect(timer, &QTimer::timeout,this,[=](){
static int num = 0;
this->setText(QString::number(num++));
});
定时器常需要使用静态局部变量 static int num=10;静态局部变量在该函数被释放时,不会被释放,直到程序运行结束以后才释放。
//.h声明了一个static bool status时
bool Widget::status = true;
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
QObject::event(QEvent *e);//return true则认为已经执行不继续往下运行
//示例,让原来的鼠标按下事件不操作
if(e->enent()==QEvent::MouseButtonPress)
return true;
事件过滤器(eventFilter)
重写虚函数 void QWidget::paintEvent(QPaintEvent *);
函数的特点:
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);//this为给画家painter设置的绘图平台
//painter.load("D:/sunny.png"); //加载图片
painter.drawPixmap(10,10,QPixmap(":/Fail/affirm.png"));
}
updata();//推荐使用,原理:调用updata就会运行了paintEvent()
repaint();
QPixmap,QImage,QPicture,QBitmap
即画布,各画布的特点:
//QPixmap
QPixmap pix(300,300);//纸张大小
QPainter painter(&pix);//新建画家
/***可以新建画笔进行设置***/
painter.drawRect(10,10,200,230);//画图
pix.save("D:/myPixmap.jpg");//保存图像
//QImage
QImage img(200,200,QImage::Format_RGB32);
//更改绘图设备,因为之前画笔在pix上,所以要重新指定绘图设备
painter.begin(&img);
/**/
painter.end();
this->setWindowFlags(Qt::FramelessWindowHint)//去窗口边框
#文件
操作:
QString fileDir = "E:/Project/qt/lesson6";
static QString fileName;
connect(ui->pushButton,&QPushButton::clicked,this,[=]()
{
fileName = QFileDialog::getOpenFileName(this, "Open File", fileDir);
ui->lineEdit->setText(fileName);
//新建文件对象
QFile file(fileName);
//设置文件打开方式
bool readOk = file.open(QIODevice::ReadOnly);
if(!readOk)
{
QMessageBox::critical(this, "Error", "文件打开失败");
}
//读文件
QByteArray context = file.readAll();//返回为utf8格式
QByteArray context += file.readLine();
ui->textEdit->setText(context);
file.close();
});
//写文件
connect(ui->writePushButton,&QPushButton::clicked,this,[=]()
{
QString newContext = ui->textEdit->toPlainText();
QFile file(fileName);
bool writeOk = file.open(QIODevice::WriteOnly);
if(!writeOk)
{
QMessageBox::critical(this, "Error", "文件写入失败");
}
file.write(newContext.toUtf8());
//file.write()
});
QTextStream myStream(&file); //将文件对象的地址传给流
myStream.setCodec("utf8"); //设置流的编码格式为utf8
while(false == myStream.atEnd())
{
QString context = myStream.readAll();
ui->textEdit->setText(context);
}
//写文件
myStream<<QString("通过流写入的字")<<1234;
QDataStream用法一样,而且可以对内存进行操作
//对内存进行读写
QImage img("D:/test.png");
QByteArray buf;
QDataStream dataStream(&buf, QIODevice::ReadWrite);
dataStream<<img;//将图像写入内存空间
QFileInfo info(“D:/lucy.png”);
成员函数:info.size();info.path();…
#include
//打印最后修改时间要包含头文件和按输出的格式写好
info.lastModified().toString("yyyy-MM-dd hh:mm:ss");
##TCP通信
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hev9Ndpp-1626187970133)( https://i.loli.net/2021/05/04/6Q3h5sLUGl7f1xI.jpg)]
QTcpServer类(需要工程包含network)
QTcpSocket类
使用
//.pro
QT += network
//main函数
Client c;
c.setWindowTitle("客户端");
c.show();
Server w;
w.setWindowTitle("服务器");
w.show();
//服务端
/*服务端需要一个监听对象指针和一个链接指针,首先新建服务端对象,再监听,如果有链接则会收到信号,然后通过链接指针接收请求,之后就可以通过链接指针进行发送和接收数据了(write和read)*/
ui->ip->setText("127.0.0.1");
ui->port->setText("6000");
//实列化
server = new QTcpServer(this);
//监听
server->listen(QHostAddress(ui->ip->text()), 6000);
//链接
connect(server,&QTcpServer::newConnection,this,[=]()
{
//接收客户端的套接字
ui->recordTextEdit->setText("有新的链接....");
conn = server->nextPendingConnection();
//发送数据
//conn->write("服务器发的数据");
ui->recordTextEdit->setText("有新的链接....");
//接收数据
connect(conn,&QTcpSocket::readyRead,this,[=]()
{
QByteArray array = conn->readAll();
ui->recordTextEdit->append("客户端me:"+array);
});
});
//发送消息
connect(ui->sendButton,&QPushButton::clicked,this,[=]()
{
conn->write(ui->textEdit->toPlainText().toUtf8());
ui->recordTextEdit->append("Host:" + ui->textEdit->toPlainText().toUtf8());
ui->textEdit->clear();
});
//客户端
/*客户端只需要链接指针,首先实列化链接指针,然后链接上服务器,即可进行文件读写*/
ui->ip->setText("127.0.0.1");
ui->port->setText("6000");
client = new QTcpSocket(this);
//链接服务器
client->connectToHost(QHostAddress(ui->ip->text()), 6000);
//ui->recordTextEdit->setText("链接上服务器");
//接收数据
connect(client,&QTcpSocket::readyRead,this,[=]()
{
QByteArray array = client->readAll();
ui->recordTextEdit->append("Host:" + array);
});
//发送数据
connect(ui->sendButton,&QPushButton::clicked,this,[=]()
{
client->write(ui->textEdit->toPlainText().toUtf8());
ui->recordTextEdit->append("me:" + ui->textEdit->toPlainText());
ui->textEdit->clear();
});
! 192.0.0.1无法设置为端口,应该是被占用了
无客户端和服务器概念,直接发信息到端口即可
QUdpSocket类
服务端和客户端都要进行:
//服务器端
ui->sIp->setText("127.0.0.9");
ui->cPort->setText("2222");
ui->sPort->setText("3333");
udp = new QUdpSocket(this);
//链接
if(udp->bind(ui->cPort->text().toInt()))
{
ui->record->setPlainText("链接成功,服务器端口为:"+ui->sPort->text().toUtf8());
}
//send msg to server
connect(ui->send,&QPushButton::clicked,this,[=]()
{
udp->writeDatagram(ui->message->toPlainText().toUtf8(),QHostAddress(ui->sIp->text()),ui->sPort->text().toInt());
});
//recieve msg from server
connect(udp, &QUdpSocket::readyRead, this, [=]()
{
char data[4096];
qint64 size = udp->pendingDatagramSize();
udp->readDatagram(data, size);
ui->record->appendPlainText(data);
});
//客户端只需要将bind的端口换为客户端端口,发送数据的端口换成服务器端口即可
?发送大文件采用udp怎么分配内存,实现udp传输一个视频
disconnectFromHost
继承QThread类
在程序处理过程中有个复杂过程,假设sleep()了,如果只有一个线程则程序直接死了,所以要采用多线程,默认线程为主线程(或称ui线程)
继承QObject类
connect(myThread,&QThread::finished,obj,&QObject::deleteLater);//子线程处理结束后,删除obj对象,因为obj没有继承窗口,不手动删除会导致内存泄漏
connect(ui->begin,&QPushButton::clicked,obj,&objThread::somethingTodo);//通过主线程控制子线程中的复杂操作开始
connect(obj,&objThread::end,this,[=]()
{
myThread->quit();
myThread->wait();
});//子线程处理结束,退出子线程
myThread->start();//启动子线程
需要用到的函数:data.chop(1) 删除字符串最后一位
链接:https://github.com/dawsoncaime/QT_EXAM
//void Widget::paintEvent(QPaintEvent *)
QPainter painter(this);
//绘制背景
painter.drawPixmap(rect(), QPixmap(":/Image/ground.png"));
...
//void Widget::keyPressEvent(QKeyEvent * event)
switch (event->key()) {
case Qt::Key_W:{
pos_next = pos + QPoint(0, -1);
if(!pos_wall.contains(pos_next)){
pos = pos_next;
}
break;
}
...
}