- 按钮类
1.1 QPushButton
1.2 QToolButton
1.3 QRadioButton
1.QRadioButton的Aotuexclusive属性(默认被勾选)自动排外,有且只有一个QRadio被Clicked。SetChecked(bool)可以设置手动排外。
- item
2.1 QWidget
- 容器类
3.1 QStackWidget
3.2 QWidget
3.3 QFrame (可带边框)
3.4 ToolBox(卡包式)
- 编辑类
4.1 QCombox
4.2 QLineEdit
4.3 QTextEdit
- 显示类
5.1 QLabel
5.2 QLcdNumber
5.3 QProgressBar
布局
1. 水平 QHBoxLayout
2. 垂直 QVBoxLayout
3. 网格
4. 详细-布局属性
5. 大小策略(Fixed固定,ExPanding扩张,Font字体,Min\MaxSize)
6. 容器(分类)
7. 弹簧 QSpacerItem
自定义控件
a) ui的控件和自定义控件的父类要相同
b) 选中ui控件-提升
常用事件处理
1) app.exec() : 一直等待事件发生
2) eventFilter(): 首先经过事件过滤器 -> 转发给各个控件
3) event(): 每个控件有本身的event() -> 调用各自的事件处理函数(一般重写派生类,写对应的虚函数比较安全)
对窗口画图
重构Widget::paintEvent
1.在窗口部件第一次显示时,系统会自动产生一个绘图事件,从而强制绘制这个窗口部件。
2.当重新调整窗口部件的大小时,系统也会产生一个绘制事件。
3.当窗口部件被其他窗口部件遮挡,然后又再次显示出来的时候,就会对那些隐藏的区域产生一个绘制事件。
4.同时可以调用QWidget::update()或者QWidget::repaint()来强制产生一个绘制事件。
重构keyPressEvent限制TextEdit输入
1.新建C++类(基类可选择QWidget,之后手动修改成QTextEdit) ->继承
2.重构虚函数 protected: ->重构
void keyPressEvent
void TcpWriteText::keyPressEvent(QKeyEvent *ev)
{
if(ev->key() >= Qt::Key_G && ev->key() <= Qt::Key_Z )
{
}
else
{
QTextEdit::keyPressEvent(ev);
}
}
3.提升为自定义控件,选择基类,输入类名,添加,设为全局,提升。
PS:使用KeyPressEvent时,要先获取焦点(有多种获得焦点方式)
setFocusPolicy(Qt::ClickFocus)//单击获取焦点
正则表达式限制LineEdit输入
#include <QValidator>
QRegExp regx("[0-9]+$");
QPointer<QValidator> pQValidator = new QRegExpValidator(regx,ui->LECustomTime);
ui->LECustomTime(LineEdit)->setValidator(pQValidator);
正则表达式去除字符串中的换行符
QStringList << Filetxt.split(QRegExp("[\r\n]"),QString::SkipEmptyParts);
判断第三点在向量的左还右
/*
* a0:向量起点
* a1:向量方向上的一点
* a2:第三点
*/
int ispostive(MyPoint a0,MyPoint a1,MyPoint a2)
{
double result = (a0.PointX - a2.PointX)*(a1.PointY - a2.PointY) - (a0.PointY - a2.PointY)*(a1.PointX - a2.PointX);
if(result >0)
{
cout << "在左";
return 1;//在左
}else if(result <0)
{
cout << "在右";
return -1;//在右
}else
{
cout << "共线";
return 0;//共线
}
}
返回相交线段之间的夹角
/*
* a0:线段1起点
* a1:两线段重合点
* a2:线段2终点
*/
double angelcal(MyPoint a0, MyPoint a1, MyPoint a2)
{
double theta = qAtan2(a0.PointX - a1.PointX, a0.PointY - a1.PointY) - qAtan2(a2.PointX - a1.PointX, a2.PointY - a1.PointY);
if (theta > M_PI)
theta -= 2 * M_PI;
if (theta < -M_PI)
theta += 2 * M_PI;
theta = abs(theta * 180.0 / M_PI);
return theta;
}
返回旋转后的坐标,坐标点绕另一坐标点逆时针旋转x度
//a0:起始点;CirCenter:圆心;angle:角度
MyPoint pointccwrotate(MyPoint a0,MyPoint CirCenter,double angle)
{
MyPoint result;
result.PointX = (a0.PointX - CirCenter.PointX)*qCos(angle/180*M_PI) - (a0.PointY - CirCenter.PointY)*qSin(angle/180*M_PI) + CirCenter.PointX;
result.PointY = (a0.PointX - CirCenter.PointX)*qSin(angle/180*M_PI) + (a0.PointY - CirCenter.PointY)*qCos(angle/180*M_PI) + CirCenter.PointY;
return result;
}
返回旋转后的坐标,坐标点绕另一坐标点顺时针旋转x度
//a0:起始点;CirCenter:圆心;angle:角度
MyPoint pointcwrotate(MyPoint a0,MyPoint CirCenter,double angle)
{
MyPoint result;
result.PointX = (a0.PointX - CirCenter.PointX)*qCos(angle/180*M_PI) + (a0.PointY - CirCenter.PointY)*qSin(angle/180*M_PI) + CirCenter.PointX;
result.PointY = (a0.PointX - CirCenter.PointX)*qSin(angle/180*M_PI) + (a0.PointY - CirCenter.PointY)*qCos(angle/180*M_PI) + CirCenter.PointY;
return result;
}
文件
//取得文件路径
QString FilePath = QFileDialog::getOpenFileName(this,"选择","../");
QPainter
QImgae对象(大小,样式)
QPainter画家对象(关联绘图设备)
QPen|QBrush画笔画刷(关联画家对象)
setpen(),setbrush(),setStyle(),setcolor()
connect
connect(),返回值FALSE/TRUE
False:链接失败,True:链接成功
发出者必须为非空非野地址,connect成功后,在任意位置都可以接收信号,触发槽函数。
--------------------------------------------------------------------------
connect()第五个参数的作用,<链接方式>:默认\队列\直接
<默认>:如果是多线程,默认使用队列;如果是单线程,默认使用直接
<Queue>:让槽函数所在的线程和接受者一样,槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。
发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。
<Direct>:让槽函数所在线程和发送者一样,槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。
效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成崩溃。
<Qt::BlockingQueuedConnection>:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。
接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
Lamda表达式默认使用Driect链接。
例: connect(&Timer,&QTimer::timeout,
[=]()
{
Timer.stop();
SendData();
bConnectOk = connect(ui->PB_Test,&QPushButton::clicked,
[=]()
{
cout << "test";
});
cout << bConnectOk;
});
只要True == bConnectOK后,只要PB_Test接收到clicked的信号,就可以触发对应的槽函数,不受上一层逻辑的影响(再无需timeout)。
多线程
//使用信号与槽,头文件必须包含'Q_OBJECT'宏
//QThread::currentThread() 可返回线程号
1)新建一个类,继承于QObject
2)创建使用的线程处理函数(只能有一个),定义一些信号函数(signals)
3)在主线程(ui)#include<新创建类的头文件>,申明该类对象。//继承Object的对象不能指定父对象
4) 创建子线程QThread对象//可以指定父对象
5) 将线程处理函数关联子线程(MoveToThread)
6) 开启子线程(QThread->strat()),使用信号与槽触发线程成立函数
7) 退出:QThread->quit() ;Linux<pthread_exit();>
8) 释放资源: QThread->wait,必要时可以将处理函数停下;Linux<pthread_join();>
QTcpSocket不能跨线程调用,也不能跨线程传址。
QTimer不能跨线程控制。"Timers cannot be started from another thread"
数据库
MYSQL:
QSqlDatabase:数据库对象
QSqlError:数据库错误对象
QSqlQuery:SQL语句对象
QVariantList:范式List
cout << QSqlDatabase::drivers();//可打印支持的数据库驱动
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");//添加数据库
db.setHostName("127.0.0.1");//数据库服务器ip
db.setUserName("root");//数据库用户名
db.setPassword("123456");//数据库密码
db.setDatabaseName("info");//用哪个数据库
db.open();//数据库是否成功打开
QSqlQuery query
***************************建表*****************************
//id:主键,自增
query.exec("create table student(id int primary key auto_increment, StuName varchar(255), age int, score int);");
***************************插入*****************************
query.exec("insert into student(StuName,age,score) values('mike',18,100);");
***************************删除*****************************
query.exec("delete from student where StuName = '%1'").arg(name);
***************************查询*****************************
query.exec("select * from student;");
//query.next()会到下一行
while(query.next() == true)
{
//取出当前行,每一列列的内容,可以排序识别,也可以用字段匹配
cout << query.value(0).toInt();
cout << query.value(1).toString();
cout << query.value("age").toInt();
cout << query.value("score").toInt();
}
***************************批量处理*****************************
//odbc风格
//1.预处理语句,'?'相当于占位符,自增主键可不赋值
query.prepare("insert into student(StuName,age,score) values(?,?,?);");
//2.给字段设置内容 List 3.给字段相应的值 按!顺序!绑定
QVariantList StuNameList;
QVariantList ageList;
QVariantList scoreList;
StuNameList << "aa" << "bb" << "cc";
ageList << 11 << 22 << 33;
scoreList << 100 << 100 << 99;
query.addBindValue(StuNameList);
query.addBindValue(ageList);
query.addBindValue(scoreList);
//执行预处理命令
query.execBatch();
//oracle风格
//占位符不同 变成(:+自定义名字)无需和字段一致
query.prepare("insert into student(StuName,age,score) values(:StuName,:age,:score);");
QVariantList StuNameList;
QVariantList ageList;
QVariantList scoreList;
StuNameList << "dd" << "ee" << "ff";
ageList << 11 << 22 << 33;
scoreList << 100 << 100 << 99;
//给字段绑定,!不局限于顺序!
query.bindValue(":StuName",StuNameList);
query.bindValue(":score",scoreList);
query.bindValue(":age",ageList);
query.execBatch();
***************************事务*****************************
/*
* 事务(Transaction),一般是指要做的或所做的事情。
* 在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)
* 事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。
*/
//本身单例,QSqlDatabase::database()实际就是操作db
//开启一个事务
QSqlDatabase::database().transaction();
等价于 query.exec("START TRANSACTION");
//开始事务
QSqlDatabase::database().commit();
等价于query.exec("COMMIT");
//回滚
QSqlDatabase::database().rollback();
等价于query.exec("ROLLBACK");
SQLITE:
//SQLITE特性主键无法自增;主要配置区别,无需用户名密码,只需设置路径
//添加本地SQLITE数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
//设置
db.setDatabaseName("../local.db");
XML
.Pro要 QT += xml
<QDomDocument>文档模型对象
<QDomProcessingInstruction>XML格式头
<QDomElement>元素
//创建元素(节点)名称
QDomElement Element = QDomDocument.createElement("str")
//创建属性名称
QDomAttr DomAttr = QDomDocument.createAttribute("str")
//设置属性内容
DomAttr.setNodeValue(Date);
//节点追加
QDomElement.append(QDomDocument)
//设置实体内容
QDomText DomText= QDomDocument.CreateText("str")
QDomElement DomElement =