是一个跨平台的 C++ 开发库,主要用来开发图形用户界面(Graphical User Interface,GUI)程序,当然也可以开发不带界面的命令行(Command User Interface,CUI)程序。
http://c.biancheng.net/view/3858.html
1~2 行:由于 main() 函数中分别定义了 QApplication 和 MainWindow 类的对象,因此需要引入 mainwindows.h 和 QApplication 头文件。mainwindow.h 文件是我们自己创建的,引入时用" "双引号括起来;QApplication 是 Qt 提供给我们的,引入时用<>括起来。
第 7 行:MainWindow 是自定义的类,继承自 QMainWindow 主窗口类,因此 MainWindow 也是一个主窗口类。w 是 MainWindow 类实例化出的对象,表示一个主窗口。
第 8 行:默认情况下,Qt 提供的所有组件(控件、部件)都是隐藏的,不会自动显示。通过调用 MainWindow 类提供的 show() 方法,w 窗口就可以在程序运行后显示出来。
初始状态下,MainWindow 类由 Q_OBJECT、构造函数和析构函数组成,这里重点介绍一下 Q_OBJECT 和构造函数:
Q_OBJECT:本质是一个已定义好的宏,所有需要“信号和槽”功能的组件都必须将 Q_OBJECT 作为 private 属性成员引入到类中。
带参的构造函数:QWidget 是所有组件的基类,借助 parent 指针,可以为当前窗口指定父窗口。
下面是 视频链接https://www.bilibili.com/video/BV1N34y1H7x7的笔记,
连接信号和槽的四种方式
注意:
1)信号与槽的参数个数和类型需要一致,至少信号的参数不能少于槽的参数。如果不匹配,会出现编译错误或运行错误。
2)使用信号和槽的类中,必须在类的定义中加入宏Q_OBJECT
1.鼠标放在组件上点击右键,选到槽,选择信号
widget.h文件中增加了:
private slots:
void on_commitPushButton_clicked();
widget.cpp文件中增加了
void Widget::on_commitPushButton_clicked()
{
}
然后需要手动补充函数:实现获取输入框的内容,并打开输入的软件
//widget.h中:
#include<QProcess>
//widget.cpp中补充函数on_commitPushButton_clicked(),
void Widget::on_commitPushButton_clicked()
{
//获取lineEdit数据 访问界面数据
QString program=ui->cmdLineEdit->text();
//创建process对象
QProcess *myProcess = new QProcess(this);
myProcess->start(program);
}
点击运行
2.使用connect连接信号和槽4个参数 谁发出 发出啥 谁处理 怎么处理
//按下回车键执行槽函数
connect(ui->cmdLineEdit,SIGNAL(returnPressed()),this,SLOT(on_commitPushButton_clicked()));
3.使用connect连接信号和槽4个参数 &符号 自动填充
//前提:需要去widget.h文件中声明函数名,在widget.cpp文件中实现槽函数也就是方法一种自动添加的两部分类似
void on_cancelPushButton_clicked();//widget.h
void Widget::on_cancelPushButton_clicked()//widget.cpp
{
this->close();//关闭窗口
}
//点击取消键执行槽函数
connect(ui->cancelPushButton,&QPushButton::clicked,this,&Widget::on_cancelPushButton_clicked);
4.使用connect连接信号和槽3个参数 当操作内容较少时,不使用处理函数
//前提:QMessageBox要在widget.h文件中声明#include
//点击浏览键,弹出信息
connect(ui->browsepushButton,&QPushButton::clicked,[this]()
{
QMessageBox::information(this,"信息","点击浏览");
});
总结widget.cpp文件:
#include "widget.h"
#include "ui_widget.h"
//构造函数
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//connect连接信号和操 谁发出 发出啥 谁处理 怎么处理
connect(ui->cmdLineEdit,SIGNAL(returnPressed()),this,SLOT(on_commitPushButton_clicked()));
//&符号
connect(ui->cancelPushButton,&QPushButton::clicked,this,&Widget::on_cancelPushButton_clicked);
//不使用槽函数
connect(ui->browsepushButton,&QPushButton::clicked,[this]()
{
QMessageBox::information(this,"信息","点击浏览");
});
}
//析构函数
Widget::~Widget()
{
delete ui;
}
void Widget::on_commitPushButton_clicked()
{
//获取lineEdit数据 访问界面数据
QString program=ui->cmdLineEdit->text();
//创建process对象
QProcess *myProcess = new QProcess(this);
myProcess->start(program);
}
void Widget::on_cancelPushButton_clicked()
{
this->close();//关闭窗口
}
1)网格的应用
2)信号和槽
3)在按钮上放图片,改变按钮背景颜色
//wedget.cpp
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//按钮上放图片
QIcon con("E:\\22cqqCode\\QtCode\\calculate\\1.png");
ui->backButton->setIcon(con);
//改变按钮的背景色
ui->equalButton->setStyleSheet("background:blue");
}
4)QString 和char *的转换
//把QString转换成char *
QByteArray byteArray;
byteArray.append(expression);//QString->QByteArray
strcpy(opt,byteArray.data());//QByteArray->QString
5)栈的应用QStack 用stack实现四则运算https://blog.csdn.net/qq_63844103/article/details/123875163
void Widget::on_equalButton_clicked()
{
QStack<int> s_num;
QStack<char> s_opt;
char opt[128]={0};
int i=0,tmp=0,num1,num2;
//把QString转换成char *
QByteArray byteArray;
byteArray.append(expression);//QString->QByteArray
strcpy(opt,byteArray.data());//QByteArray->QString
/*四则运算用栈实现
* 将中缀表达式转为后缀表达式->计算后缀表达式
* 1.数字(直接入栈s_num)
* 2.运算符(s_opt栈空直接入栈,非空若当前运算符大于s_opt栈顶的优先级才可入栈)
* 3.'('(直接入栈s_opt)
* 4.')'(一直弹出栈顶元素,直到遇到'(',将其弹出后,继续遍历字符串)
* 5.遍历结束,依次弹出栈内元素
* 从s_opt中每弹出一个运算符(除左括号外),就要从s_num中弹出两个数字参与运算,并将结果放回s_num中
*/
while(opt[i]!='\0'||s_opt.isEmpty()!=true){
if(opt[i]>='0'&&opt[i]<='9'){//数字
tmp=tmp*10+opt[i]-'0';
i++;
if(opt[i]<'0'||opt[i]>'9'){
s_num.push(tmp);
tmp=0;
}
}
else{//运算符
if(s_opt.isEmpty()==true||Priority(opt[i])>Priority(s_opt.top())||
(s_opt.top()=='(' && opt[i]!=')')){
s_opt.push(opt[i]);
i++;
continue;
}//将运算符入栈
if(s_opt.top()=='('&&opt[i]==')'){
s_opt.pop();
i++;
continue;
}//将运算符'('出栈
if(Priority(opt[i])<=Priority(s_opt.top())||(opt[i]==')'&&s_opt.top()!='(')
||(opt[i]=='\0'&&s_opt.isEmpty()!=true)){
num2=s_num.pop();
num1=s_num.pop();
switch (s_opt.pop()) {
case '+':
s_num.push(num1+num2);
break;
case '-':
s_num.push(num1-num2);
break;
case '*':
s_num.push(num1*num2);
break;
case '/':
s_num.push(num1/num2);
break;
default:
break;
}
}//将其他运算符出栈,并弹出两个元素进行计算
}
}
ui->showLineEdit->setText(QString::number(s_num.top()));
expression.clear();
}
int Widget:: Priority(char ch){//优先级函数
switch (ch) {
case '(': return 3;
case '*':
case '/': return 2;
case '+':
case '-': return 1;
default:
return 0;
}
}
1)在label标签上放图片方法一
QPixmap pix("E:\\22cqqCode\\QtCode\\objectTimer\\1.jpeg");
ui->label->setPixmap(pix);
2)用QObject定时器实现图片1秒钟切换一次
总结widget.cpp文件:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//放图片
pixId=2;
QPixmap pix("E:\\22cqqCode\\QtCode\\objectTimer\\1.jpeg");
ui->label->setPixmap(pix);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_startButton_clicked()
{
//开启定时器,返回定时器编号
myTimerId = this->startTimer(TIMEOUT);
}
void Widget::timerEvent(QTimerEvent *event)
{
if(event->timerId()!=myTimerId)
return ;
//更新图片
QString path("E:\\22cqqCode\\QtCode\\objectTimer\\");
path+=QString::number(pixId);
path+=".jpeg";
QPixmap pix(path);
ui->label->setPixmap(pix);
pixId++;
if(6==pixId) pixId=1;
}
void Widget::on_stopButton_clicked()
{
this->killTimer(myTimerId);
}
QObject定时器主要是三个函数,开始startTimer,触发事件,结束killTimer
1)在label标签上放图片方法二
QImage img;
img.load("E:\\22cqqCode\\QtCode\\objectTimer\\1.jpeg");
ui->label->setPixmap(QPixmap::fromImage(img));
2)用QTimer定时器实现图片1秒钟切换一次;
用QTimer定时器实现图片1秒钟切换,只切换一次
widget.h文件中的槽函数和成员变量
总结widget.cpp文件:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
timer=new QTimer;//指针初始化
//放图片
QImage img;
img.load("E:\\22cqqCode\\QtCode\\objectTimer\\1.jpeg");
ui->label->setPixmap(QPixmap::fromImage(img));
pixId=2;
//定时器时间到,发出timeout信号
connect(timer,&QTimer::timeout,this,&Widget::timeoutSlot);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_startButton_clicked()
{
timer->start(TIMEOUT);//开始定时器,时间为TIMEOUT=1000ms
}
void Widget::timeoutSlot()
{
QString path;
path="E:\\22cqqCode\\QtCode\\objectTimer\\";
path+=QString::number(pixId);
path+=".jpeg";
QImage img;
img.load(path);
ui->label->setPixmap(QPixmap::fromImage(img));
pixId++;
if(pixId==6) pixId=1;
}
void Widget::on_endButton_clicked()
{
timer->stop();//结束
}
void Widget::on_singleButton_clicked()
{
QTimer::singleShot(1000,this,SLOT(timeoutSlot()));//单次执行超时触发函数
}
1)QMainWindow菜单栏
2)通过connect连接信号和槽
connect(ui->newAction,&QAction::triggered,this,&MainWindow::newActionSlot);
connect(ui->openAction,&QAction::triggered,this,&MainWindow::openActionSlot);
connect(ui->saveAction,&QAction::triggered,this,&MainWindow::saveActionSlot);
3)读文件和写文件
//读文件
QString fileName=QFileDialog::getOpenFileName(this,"选择一个文件",
QCoreApplication::applicationFilePath(),"*.cpp");
//写文件
QString fileName=QFileDialog::getSaveFileName(this,"选择一个文件",
QCoreApplication::applicationFilePath());
4)鼠标事件QMouseEvent,键盘事件QKeyEvent,ctrl+S实现保存
总结widget.cpp文件:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//被单击的时候触发事件
connect(ui->newAction,&QAction::triggered,this,&MainWindow::newActionSlot);
connect(ui->openAction,&QAction::triggered,this,&MainWindow::openActionSlot);
connect(ui->saveAction,&QAction::triggered,this,&MainWindow::saveActionSlot);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::newActionSlot()
{
ui->textEdit->clear();
this->setWindowTitle("新建文本文档.txt");
}
void MainWindow::openActionSlot()
{
QString fileName=QFileDialog::getOpenFileName(this,"选择一个文件",
QCoreApplication::applicationFilePath());
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::saveActionSlot()
{
QString fileName=QFileDialog::getSaveFileName(this,"选择一个文件",
QCoreApplication::applicationFilePath());
if(fileName.isEmpty()){
QMessageBox::warning(this,"警告","请选择一个文件");
}
else{
QFile file(fileName);
file.open(QIODevice::WriteOnly);
QByteArray ba;
ba.append(ui->textEdit->toPlainText());
file.write(ba);
file.close();
}
}
void MainWindow::keyPressEvent(QKeyEvent *k)
{
if(k->modifiers()==Qt::ControlModifier&&k->key()==Qt::Key_S){
saveActionSlot();
}
}
void MainWindow::mousePressEvent(QMouseEvent *m)
{
QPoint pt=m->pos();
qDebug()<<pt;
if(m->button()==Qt::LeftButton){
qDebug()<<"左键被按下";
}
if(m->button()==Qt::RightButton){
qDebug()<<"右键被按下";
}
}
1)TCP服务器 socket bind listen accept send/recv
TCP客户端 socket connect send/recv
服务器和客户端的ui界面
涉及到网络操作需要在工程文件中添加network
2)客户端发出连接, 连接成功发出connected,连接断开发出disconnected信号
3)服务器监听ip地址和端口号
4)客户端向服务器发送信息,创建新的窗口
修改槽函数,连接成功的时候出现聊天界面
chat.cpp文件中的发送按钮触发的槽函数
总结,
//服务器收到客户端发送的信息,socket发出readyread信号
connect(socket,&QTcpSocket::readyRead,this,&Widget::clientInfoSlot);
void Widget::clientInfoSlot()
{
//获取信号的发出者
QTcpSocket *s=qobject_cast<QTcpSocket *>(sender());//强制类型转换
ui->mainLineEdit->setText(QString( s->readAll()));
}
服务器端使用多线程
mythread.h文件
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include
#include
#include
class myThread : public QThread
{
Q_OBJECT
public:
explicit myThread(QTcpSocket *s);
void run();//线程处理函数
signals:
public 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);
}
//无法通过ui打印在界面上 ,不能在其他类里面操作界面
void myThread::clientInfoSlot()
{
QByteArray ba=socket->readAll();
qDebug()<<QString(ba);//信息显示在服务器的输出端
}
在widget.cpp文件中连接成功的槽函数中启动线程
缺陷是:不能在其他类里面操作界面,也就是无法在mythread中操作ui界面,使得客户端发送的信息能够显示在服务器界面上
解决:下面的自定义信号,然后通过emit关键字发送信号
实现将对象t中的内容发送到对象w中显示出来
mythread.h文件中添加自定义信号
mythread.cpp文件中需要修改部分
widget.cpp构造函数中修改部分以及threadSlot(QByteArray b)函数
数据的显示是服务器后台的线程收到信息,线程通过信号把数据发送到窗口,窗口通过控件显示数据
1)涉及到数据库操作需要在工程文件中添加sql
2)widget.cpp文件中数据库连接的操作
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//连接数据库
db=QSqlDatabase::addDatabase("QMYSQL");//加载MySQL数据库驱动
db.setDatabaseName("mydatabase");//数据库名
db.setPort(3306);//端口号
db.setHostName("localhost");//主机名
db.setUserName("root");//用户名
db.setPassword("root");//用户密码
if(db.open())
{
QMessageBox::information(this,"连接提示","连接成功");
}
else
{
QMessageBox::warning(this,"连接提示","连接失败");
}
}
Widget::~Widget()
{
delete ui;
}
//查询
void Widget::on_selectButton_clicked()
{
QSqlQuery query;
query.exec("select * from student;");//query.exec执行
while (query.next()) {//query.next指向结果集的下一条记录
qDebug()<<query.value(0)<<query.value(1)<<query.value(2);//query.value
}
}
//插入
void Widget::on_insertButton_clicked()
{
QString id=ui->idLineEdit->text();
QString name=ui->nameLineEdit->text();
QString birth=ui->birthLineEdit->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::warning(this,"插入提示","插入失败");
}
}
3)
1)QTableView
2)widget.h文件
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
QSqlTableModel *m;
};
#endif // WIDGET_H
3)widget.cpp文件
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL");//加载MySQL数据库驱动
db.setDatabaseName("mydatabase");
db.setPort(3306);
db.setHostName("localhost");
db.setUserName("root");
db.setPassword("root");
if(db.open())
{
QMessageBox::information(this,"连接提示","连接成功");
m=new QSqlTableModel(this);
m->setTable("student");//与表连接
ui->tableView->setModel(m);
}
else
{
QMessageBox::warning(this,"连接提示","连接失败");
}
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
m->select();
}
4)关键