Qt中的常用快捷键
注释:ctrl + /
运行:ctrl + r
编译:ctrl + b
帮助文档:F1
自动对齐:ctrl + i
同名之间.h文件与.cpp文件的切换:F4
QPushButton按钮
需要引入<QPushButton>头文件,QPushButton继承于QWidget类
创建一个按钮
QPushButton * btn = new QPushButton();
QPushButton* btn2 = new QPushButton("第二个按钮", this);
显示按钮
btn->show();
要想按钮显示在指定窗口中,需要指定父类
btn->setParent(this);
btn->setText("第一个按钮");
设置按钮位置
坐标是以左上角为(0,0)
btn2->move(100, 100);
窗口和按钮大小
resize(600, 400);
btn2->resize(50,50);
setFixedSize(600, 400);
设置窗口标题
setWindowTitle("第一个窗口");
对象树
1、当创建的对象在堆区时,如果指定的对象是QObject或者其子类派生下来的类,可以不用管理释放的操作,将对象放入到对象树中。
2、对象树的构造是现有父类再有子类的,析构顺序是先析构子类再析构父类。
3、当析构函数中有输出语句时,先打印父类的析构语句,但这并不意味着析构顺序。西沟的顺序依然是先子类后父类。
4、对象树一定程度上简化了内存回收机制。
信号和槽
信号槽的优点:松散耦合。
什么是松散耦合:信号的发送端 和 接收端本身是没有关联的,通过connect连接将两端耦合在一起。
connect(发送者, 发送的信号, 接收者, 信号的处理(槽));
- 参数1:信号的发送者
- 参数2:发送的信号(存放函数的地址)(clicked点击,pressed按下,released弹起,toggled切换)
- 参数3:信号的接收者
- 参数4:处理的槽函数(函数地址)
connect(myBtn, &PushButton::clicked, this, &Widget::close);
disconnect(btn, &QPushButton::clicked, this, &Widget::classIsOver);
connect(zt, SIGNAL(hungry()), st, SLOT(treat()));
Qt4版本的优点,直观。缺点,类型不做检测
自定义信号
自定义信号使用signals关键字修饰
规定:
1、没有返回值;
2、只需要声明不需要实现;
3、可以有参数;
4、可以重载;
signals:
void hungry();
void hungry(QString foodName);
自定义槽函数
规定:
1、无返回值;
2、需要声明也需要实现;
3、可以有参数;
4、可以发生重载;
public slots:
void treat();
void treat(QString foodName);
重载后的槽函数连接时需要指明函数类型
this->zt = new Teacher(this);
this->st = new Student(this);
void (Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
void (Student:: *studentSlots)(QString) = &Student::treat;
connect(zt, teacherSignal, st, studentSlots);
void (Teacher:: *teacherSignal2)(void) = &Teacher::hungry;
void (Student:: *studentSlots2)(void) = &Student::treat;
connect(zt, teacherSignal2, st, studentSlots2);
槽函数必须有对应的实现。
使用时用connect将信号与槽函数连接在一起即可。
信号的发送
使用emit
emit zt->hungry();
emit zt->hungry("有参的信号");
信号和槽的连接
1、信号连接多个槽函数
2、多个信号连接同一个槽函数
3、信号连接信号
注意: 信号的参数可以多于槽,但是必须一一对应
Lambda表达式
[=](){
btn->setText("下课111");
}();
[&](){
btn2->setText("下课222");
}();
[btn](){
btn->setText("下课222");
}();
[=]()mutable{
btn->setText("下课111");
}();
int ret = []()->int{return 1000;}();
qDebug() << ret << endl;
菜单栏
一个程序中菜单栏 只能最多有一个
QMenuBar *bar = menuBar();
setMenuBar(bar);
QMenu * fileMenu = bar->addMenu("文件");
QMenu * editMenu = bar->addMenu("编辑");
QAction* newAction = fileMenu->addAction("新建");
fileMenu->addSeparator();
QAction* openAction = fileMenu->addAction("打开");
工具栏
工具栏可以有多个
QToolBar* toolBar = new QToolBar(this);
addToolBar(Qt::LeftToolBarArea, toolBar);
toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
toolBar->setFloatable(false);
toolBar->setMovable(false);
toolBar->addAction(newAction);
toolBar->addAction(openAction);
toolBar->addSeparator();
toolBar->addAction("自己");
QPushButton * btn = new QPushButton("aa", this);
toolBar->addWidget(btn);
状态栏
可以有多个
QStatusBar* stBar = statusBar();
setStatusBar(stBar);
QLabel* label = new QLabel("提示", this);
stBar->addWidget(label);
QLabel* label2 = new QLabel("右侧提示", this);
stBar->addPermanentWidget(label2);
铆接部件
QDockWidget* dockWidget = new QDockWidget("浮动",this);
addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
dockWidget->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
核心部件
只能有一个
QTextEdit* edit = new QTextEdit(this);
setCentralWidget(edit);
各个栏的布局情况
添加资源文件
第一步:先将资源复制到项目所在文件夹
第二步:在Qt中右键项目—>添加新文件(Add New…),出现如下界面
第三步:名称自己起,添加成功后Qt列表会多出资源的文件夹
第四步:右键.qrc资源文件
第五步:添加前缀可以自定义,先添加前缀再添加文件
然后保存编译一下,就能看到项目列表中的资源文件了。
资源文件的使用
路径前必须写 ( “:” + “前缀”)
ui->actionnew->setIcon(QIcon(":/img/1.jpg"));
对话框
Qt都提供了哪些标准对话框:
- QColorDialog:选择颜色对话框。
- QFileDialog:选择文件对话框。
- QFontDialog:选择字体对话框。
- QInputDialog:允许用户输入一个值,并将其值返回。
- QMessageBox:消息(模态)对话框,用于显示信息,或询问等。
- QPageSetupDialog:为打印机提供纸张相关选项。
- QPrintDialog:打印机配置。
- QPrintPreviewDialog:打印预览。
- QProgressDialog:显示操作过程。
1、模态对话框:该对话框弹出后必须响应,否则不能点其他的窗口
connect(ui->actionnew, &QAction::triggered, [=](){
QDialog dlg(this);
dlg.resize(200, 100);
dlg.exec();
qDebug() << "模态对话框操作完毕!";});
2、非模态对话框:该对话框弹出后可以不响应,依然可以点击其他窗口
connect(ui->actionnew, &QAction::triggered, [=](){
QDialog *dlg2 = new QDialog(this);
dlg2->resize(200, 100);
dlg2->show();
qDebug() << "非模态对话框执行了!" << endl;});
注意:
如果不停的点击按钮触发非模态对话框,就会不停的new空间,
但是对象树是在程序结束时统一释放的,
所以这个对象就有可能导致内存溢出,
解决方法:
设置Attribute属性,在对话框关闭的时候就释放申请的空间
dlg2->setAttribute(Qt::WA_DeleteOnClose);
3、消息对话框
connect(ui->actionww, &QAction::triggered, this, [=]{
QMessageBox::critical(this, "hello", "错误:");
});
返回值:选项;参数1:指定父类;参数2:对话框标题;参数3:显示的内容;参数4:选项;参数5:关联回车的选项;
其他都类似,列举一下:
QMessageBox::information(this, "information", "信息:");
QMessageBox::question(this, "question", "请问:");
QMessageBox::warning(this, "warning", "警告:");
提问对话框可以修改选项值,默认为yes|no
QMessageBox::question(this, "question", "请问:",
QMessageBox::Save|QMessageBox::Cancel);
提问对话框的第五参数表示默认关联回车的选项
QMessageBox::question(this, "question", "请问:",
QMessageBox::Save|QMessageBox::Cancel,
QMessageBox::Cancel);
其他对话框
QColor color = QColorDialog::getColor(QColor(255,0,0,2));
qDebug() << color.red() << color.green() << color.blue() << color.alpha() << endl;
QString str = QFileDialog::getOpenFileName(this, "D:/DeskTop", "(*.txt)");
qDebug() << "str: " << str << endl;
bool flag = true;
QFont font = QFontDialog::getFont(&flag, QFont("华文彩云", 36));
qDebug() << "字体:" << font.family().toUtf8().data() << "字号:" << font.pointSize()
<< "是否加粗:" << font.bold() << "是否倾斜:" << font.italic() << endl;
界面布局
对齐方式
运行结果
若想将用户名和密码框都对齐,可将这4个组件拖入一个widget中进行栅格布局。
自定义控件
右键项目—>添加新文件(Add New…)—>选Qt—>设计师界面类—>确定。
然后给自己的ui界面起一个名字
创建成功后就出现了一个新的ui
在自己创建的ui文件中自定义拖拽想要封装的控件组合成一个新的控件。
记下自己创建的是什么控件类型
然后点击进入程序默认创建的ui文件
因为我创建的控件类型是widget
右键widget控件—>提升为
成功后可以看到这个控件的类型变成了自定义控件类型
运行看结果,封装成功
若想给自定义控件加功能,在自定义的类中写逻辑代码即可。
void (QSpinBox::* sp)(int) = &QSpinBox::valueChanged;
connect(ui->spinBox, sp, ui->horizontalSlider, &QSlider::setValue);
connect(ui->horizontalSlider, &QSlider::valueChanged, ui->spinBox, &QSpinBox::setValue);
Qt中的鼠标事件
myLabel::myLabel(QWidget* parent): QLabel(parent)
{
setMouseTracking(true);
}
void myLabel::enterEvent(QEvent* event){
}
void myLabel::leaveEvent(QEvent*){
}
void myLabel::mouseMoveEvent(QMouseEvent *ev){
QString str;
if(ev->buttons() & Qt::LeftButton)
str = QString("鼠标释放了 x = %1 y = %2 "
"globalx = %3 global = %4")
.arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
qDebug() << "鼠标移动了" << endl;
}
void myLabel::mousePressEvent(QMouseEvent *ev){
QString str;
if(ev->button() == Qt::LeftButton)
str = QString("鼠标按下了 x = %1 y = %2 "
"globalx = %3 global = %4")
.arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
qDebug() << str << endl;
}
void myLabel::mouseReleaseEvent(QMouseEvent *ev){
QString str;
if(ev->button() == Qt::RightButton)
str = QString("鼠标释放了 x = %1 y = %2 "
"globalx = %3 global = %4")
.arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
qDebug() << str << endl;
}
定时器
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
startTimer(1000);
}
void Widget::timerEvent(QTimerEvent *){
static int num = 1;
ui->label_2->setText(QString::number(num++));
}
startTimer()函数返回值是定时器的唯一标识,当有多个定时器时可以用来做区分
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
id1 = startTimer(1000);
id2 = startTimer(2000);
}
void Widget::timerEvent(QTimerEvent * ev){
if(ev->timerId() == id1){
static int num = 1;
ui->label_2->setText(QString::number(num++));
}
if(ev->timerId() == id2){
static int num2 = 1;
ui->label_3->setText(QString::number(num2++));
}
}
实际上,当startTimer函数调用后会启动一个全局唯一的定时器,在指定时间间隔后调用定时器事件,事件函数可通过timerId函数来区分是哪个定时器调用的当前事件。
按时间间隔重复调用事件函数。
定时器的另一种实现 (推荐使用)
QTimer *time = new QTimer(this);
time->start(500);
connect(time, &QTimer::timeout, this, [=](){
static int num = 1;
ui->label_4->setText(QString::number(num++));
});
event事件分发器
事件拦截 (不建议实际使用,仅供学习练习)
不让事件分发器继续向下分发
bool myLabel::event(QEvent *e){
if(e->type() == QEvent::MouseButtonPress){
qDebug() << "鼠标按下事件被拦截了" << endl;
return true;
}
return QLabel::event(e);
}
事件过滤器
ui->label->installEventFilter(this);
}
bool Widget::eventFilter(QObject* obj, QEvent* e){
if(obj == ui->label){
if(e->type() == QEvent::MouseButtonPress){
qDebug() << "事件过滤:" << endl;
QMouseEvent* ev = static_cast<QMouseEvent *>(e);
QString str = QString("鼠标按下了 x = %1 y = %2 "
"globalx = %3 global = %4")
.arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
qDebug() << str << endl;
return true;
}
}
return QWidget::eventFilter(obj,e);
}
绘图事件
只需重写paintEvent函数,系统会自动调用。
void Widget::paintEvent(QPaintEvent*){
QPainter painter(this);
QPen pen(QColor(255, 0, 0));
pen.setWidth(3);
pen.setStyle(Qt::DotLine);
painter.setPen(pen);
QBrush brush(QColor(0,255,0));
brush.setStyle(Qt::Dense7Pattern);
painter.setBrush(brush);
painter.drawLine(QPoint(0,0), QPoint(100,100));
painter.drawEllipse(QPoint(100,100), 50, 50);
painter.drawRect(QRect(20,20,60,50));
painter.drawText(QRect(10, 200, 200, 50), "好好学习,天天向上");
}
高级绘图
void Widget::paintEvent(QPaintEvent*){
QPainter pain(this);
pain.drawEllipse(QPoint(100,50), 50, 50);
pain.setRenderHint(QPainter::Antialiasing);
pain.drawEllipse(QPoint(200,50), 50, 50);
pain.drawRect(QRect(100, 150, 60, 30));
pain.translate(200, 0);
pain.drawRect(QRect(100, 150, 60, 30));
pain.translate(200, 0);
pain.save();
pain.drawRect(QRect(100, 150, 60, 30));
pain.translate(200, 0);
pain.restore();
pain.drawRect(QRect(100, 150, 60, 30));
}
画资源图片
void Widget::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.drawPixmap(posx, 100, QPixmap(":/img/2.jpg"));
}
手动调用绘画事件
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->pushButton, &QPushButton::clicked, this, [=](){
posx+=20;
update();
});
}
绘图设备
Qt在进行绘图操作的时候实际上是使用Qpainter在QPainterDevice上进行绘制,它们之间使用QPaintEngine进行通讯。
绘图设备是指继承QPainterDevice的子类,Qt一共提供了4个这样的类。
- QPixmap:专门为图像在屏幕上的显示做了优化。
- QBitmap:是QPixmap的一个子类,它的色深限定为1,可以使用QPixmap的isQBitmap()函数来确定这个QPixmap是不是一个QBitmap。只有黑色和白色。
- QImage:专门为图像的像素级访问做了优化。可以访问具体的像素点。
- QPicture:则可以记录和重现QPainter的各条命令。
QPixmap
主要是专门为了平台做显示上的优化。
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPixmap pix(300, 300);
pix.fill(Qt::white);
QPainter painter(&pix);
painter.setPen(QPen(Qt::green));
painter.drawEllipse(QPoint(150,150), 100, 100);
pix.save("D:\\test.png");
}
上述代码运行后并不会出现任何结果,而是将这个绘图保存到了D:\\test.png路径下。
图像文件在Pixmap和Bitmap的不同表现
void Widget::paintEvent(QPaintEvent *event){
QPixmap pixmap(":/img/1.jpg");
QBitmap bitmap(":/img/1.jpg");
QPainter * pain = new QPainter(this);
pain->drawPixmap(0, 0, pixmap);
pain->drawPixmap(0,400, bitmap);
}
QImage
对像素点进行操作
void Widget::paintEvent(QPaintEvent *event){
QPainter *paint = new QPainter(this);
QImage img;
img.load(":/img/1.jpg");
for(int i = 50; i < 200; ++i){
for(int j = 0; j < 200; ++j){
QRgb value = qRgb(0, 255, 0);
img.setPixel(i, j, value);
}
}
paint->drawImage(0,0,img);
}
可以看到有一坨被改成了绿色。
QPictrue
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPicture pic;
QPainter paint;
paint.begin(&pic);
paint.setPen(QPen(Qt::cyan));
paint.drawEllipse(QPoint(150,150), 100, 100);
paint.end();
pic.save("D:\\pic");
}
执行过上述指令后将在指定路径生成pic文件,现在利用这个文件重新执行绘图指令
void Widget::paintEvent(QPaintEvent *event){
QPainter paint(this);
QPicture pic;
pic.load("D:\\pic");
paint.drawPicture(0,0, pic);
}
文件读写
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->pushButton, &QPushButton::clicked, [=](){
QString path = QFileDialog::getOpenFileName(this, "打开文件", "D:\\DeskTop");
ui->lineEdit->setText(path);
QFile file(path);
file.open(QIODevice::ReadOnly);
QByteArray array = file.readAll();
ui->textEdit->setText(array);
});
}
运行结果:
默认读取的是utf-8的格式,若读取gbk格式将出现乱码
下面是读取GBK格式的写法,使用QTextCodec类指定文件的编码格式
connect(ui->pushButton, &QPushButton::clicked, [=](){
QString path = QFileDialog::getOpenFileName(this, "打开文件", "D:/code/qtStudy");
ui->lineEdit->setText(path);
QTextCodec* codec = QTextCodec::codecForName("gbk");
QFile file(path);
file.open(QIODevice::ReadOnly);
QByteArray array = file.readAll();
ui->textEdit->setText(codec->toUnicode(array));
});
写文件
file.open(QIODevice::Append);
file.write("aaa");
file.close();
文件的具体操作
QFileInfo info(path);
qDebug() << "大小:" << info.size()
<< "后缀名:" << info.suffix()
<< "文件名称:" << info.fileName()
<< "文件路径:" << info.filePath()
<< "创建日期:" << info.created().toString("yyyy/MM/dd hh:mm:ss")
<< "修改日期:" << info.lastModified().toString("yyyy-MM-dd hh:mm:ss")
<< endl;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)